从路由器出口(NG5)导航到父路径

Navigate to parent path from router outlet (NG5)

问题

正在尝试从 http://localhost:4200/#/place/(popup:tabs-modal) 导航 (一个插座)http://localhost:4200/#/place/someId

请注意,出口基本上是通往 "place" 的子路线。

我能做什么

我可以关闭插座,然后结束:http://localhost:4200/#/placethis.router.navigate(['place', { outlets: { popup: null } }]);

哦,那很简单吧?

this.router.navigate(['place', 'someId', { outlets: { popup: null } }]);然后应该导航到 http://localhost:4200/#/place/someId 对吗?

错了。路由器为我生成了一条无意义的路由:"/place/(someId//popup:tabs-modal)"

我是不是做错了什么?或者它只是越野车?

我放弃了让 .navigate() 工作的尝试,最终改用 router.navigateByUrl('/place/someId')。一个让我望而却步的简单解决方案。

this.router.navigate(['/', 'place', { outlets: { popup: null } }]);

您需要从根路径引导

编辑:

angular 路由器上有一个未解决的问题,希望通过此拉取请求修复:https://github.com/angular/angular/pull/22394

与空路由器插座有关的问题。您还需要知道相对路径仅相对于路由器树 (ActiveRoutes) 而不是 URL。考虑到这一点,我创建了一个辅助函数来解决这个问题,直到它在 Angular 6.

中得到修复

import { Router, ActivatedRoute } from '@angular/router';
/**
 *
 * Angular Relative path tempory solution. Angular doesn't like empty paths.
 * Should be fixed in version 6 Pull request 22394
 * https://github.com/angular/angular/pull/22394
 *
 * Angular Issue: https://github.com/angular/angular/issues/13011#issuecomment-274414952
 *
 * Before removing check relative paths work on named outlet. Using Navigate on named
 * outlet currently relates to secondary routes (outlet:'route/test)
 * this meant breaking out wasn't possiable using ../../ like documented in
 * angular own documentation
 *
 * key Information: This is relative to routes like anuglar intended NOT URL path
 *
 * Bug only relates to going to parent and down the tree
 *
 * @export NavigateByRelative
 * @param {string} path
 * @param {Router} router
 * @param {ActivatedRoute} route
 *
 */
export function NavigateByRelative(path: string, router: Router, route: ActivatedRoute) {

    /**
     * Relative paths should always start with '../' as per angular documentation
     * https://angular.io/guide/router#relative-navigation
     */
    if (path.startsWith('../')) {
        // split path into multiple paths
        const paths = path.split('/');

        // minus 1 on length as we gurantee need the last index
        const totalPathToLastIndex = paths.length - 1;

        // current index so we can start at this later on
        let currentPathIndex;

        // Relative to is so we get to the correct parent
        let relativeTo = route;

        // Check their is a parent and the current path still intended to go back up the tree
        for (currentPathIndex = 0;
            currentPathIndex < totalPathToLastIndex
            && relativeTo.parent !== undefined
            && paths[currentPathIndex] === '..';
            currentPathIndex++
        ) {
            relativeTo = relativeTo.parent;
        }

        // Navigate starting at the the currentpathIndex and relative to the current parent
        router.navigate([...paths.splice(currentPathIndex )], { relativeTo });

    } else {
        // else use navigation as normal as this should work correctly
        router.navigate([path]);
    }
}

更新:2018 年 10 月 23 日 抱歉耽搁了。自 angular 6 起,路由器导航的问题现已解决

更新:2019 年 2 月 4 日 Angular7+又引入了bug

接受的答案是不好的做法,因为您肯定不想在您想关闭弹出窗口或其他任何内容时使用 navigateByUrl。最好的办法是在你的路由器中做这样的事情:

{
        path: 'place/:someid',
        component: PlacePageComponent,
        resolve: {someid: SomeIDResolver},
        children: [
            {
                path: 'tabs-modal/:maybenextidhere',
                outlet: 'popup',
                component: TabsModalComponent,
                resolve: {maybenextidhere: MaybeNextIDResolver},
            },
        ]
    },

然后技巧就来了。在你想要关闭弹出窗口的函数中,你想要调用这样的东西:

this.router.navigate(['./', {outlets: { popup: null}}], {relativeTo: this.route.firstChild.firstChild});

我遇到了同样的问题。问题是我希望能够在任何深度使用我的组件。因此 解决方案让我创建了一种稍微不同但更灵活的方法。

Helper 方法通过 ActivatedRoute 和 returns 查找 relativeTo 属性 所需的 ActivatedRoute 以正确导航出辅助出口。

private getRelativeTo(
  obj: ActivatedRoute,
  callback: (lastFirstChild: ActivatedRoute) => void
) {
  Object.keys(obj).forEach((key) => {
    if (key === 'outlet') {
      if (obj[key] === PRIMARY_OUTLET) {
        const fChild = obj.firstChild;
        const nextFChild = fChild ? fChild!.firstChild : undefined;
        if (fChild && nextFChild) {
          nextFChild.outlet === 'modal' // name of your secondary outlet
            ? callback(fChild) // found child component with named outlet
            : this.getRelativeTo(fChild, callback) // not found, go deeper
        } else {
          // No named child outlet found so just return back.
          callback(this.route);
        }
      } else {
        // First child is not the primary, so just return back.
        callback(this.route);
      }
    }
  });
}

这就是我使用它关闭模态的方式:


...

constructor(
  private router: Router,
  private route: ActivatedRoute
) {}

closeModal() {
  this.getRelativeTo(this.route, (lastFirstChild) => {
    this.router.navigate(['./', { outlets: { modal: null } }], {
      replaceUrl: true,
      relativeTo: lastFirstChild,
    });
  });
}

这种方法帮助我在与主出口相同的级别上使用时以及用作子组件时使用命名辅助出口正确地从子路由中导航出来。

希望对您有所帮助。