Angular 2可选路径参数


180

Angular 2路线中是否可以有一个可选的路线参数?我在RouteConfig中尝试了Angular 1.x语法,但收到以下错误:

“原始例外:路径“ / user /:id?”包含“?”,这是路由配置中不允许的。”

@RouteConfig([
{
    path: '/user/:id?',
    component: User,
    as: 'User'
}])

Answers:


297

您可以使用和不使用参数来定义多个路由:

@RouteConfig([
    { path: '/user/:id', component: User, name: 'User' },
    { path: '/user', component: User, name: 'Usernew' }
])

并处理组件中的可选参数:

constructor(params: RouteParams) {
    var paramId = params.get("id");

    if (paramId) {
        ...
    }
}

另请参阅相关的github问题:https : //github.com/angular/angular/issues/3525


11
如果我错了,请纠正我,但是这种解决方案仅在数组中的路由顺序相反时(即,带有参数的路由在另一个之前出现)才对我有用。直到我这样做,路由器才匹配没有参数的路由。
Aviad P.

10
此解决方案仍然适用吗?我注意到从“用户”转到“ UserNew”将重新实例化“用户”组件
teleaziz

19
这种方法过时,但主要的问题是每条路径都被视为唯一的路径,并且使得组件无法重用。
痛苦的

4
如@teleaziz指出的那样,附加参数将重新呈现组件。为了避免这种情况,马丁·克雷默(Martin Cremer)的回答是:添加带有空白参数值的'redirectTo'根目录对我来说非常有用:stackoverflow.com/a/49159166/1364650-但这很不客气,我认为它们应该只支持可选的路由参数。
Vincent Sels

2
对于那些想知道为什么RouteParams不导入组件的人,请检查以下内容:stackoverflow.com/a/36792261/806202。解决方案是使用ActivatedRouteroute.snapshot.params['routeParam']
Arsen Khachaturyan

89
{path: 'users', redirectTo: 'users/', pathMatch: 'full'},
{path: 'users/:userId', component: UserComponent}

这样,添加参数时就不会重新渲染组件。


6
这个答案是最好的。它不会重新渲染相同的组件,也不需要多个组件。
Rex

4
最好的答案,但我添加pathMatch: 'full'了重定向,否则users/admin在我的情况下也将重定向类似的路径
Valeriy Katkov

4
仅当您可以在浏览器中查看URL的斜杠时,此答案才是最佳答案。考虑一个代表“未定义ID”的值,例如/users/all/users/home,将“ all”或“ home”读为id,如果它与您的魔术值匹配,则将其忽略。然后,上面的第一行变为redirectTo: 'users/home'您决定的内容。在我看来,尾随的斜线确实出了点问题。
Simon_Weaver

@Simon_Weaver我同意。我发现了另一个使用匹配器的解决方案,它没有这个问题:stackoverflow.com/a/56391974/664533
韦恩·莫雷尔

1
这是一个简单的咒语,但牢不可破:D最佳解决方案!
Verri

45

如果信息是可选的,建议使用查询参数。

路由参数还是查询参数?

没有硬性规定。一般来说,

首选路由参数

  • 该值是必需的。
  • 该值是区分一条路径与另一条路径所必需的。

首选查询参数

  • 该值是可选的。
  • 该值是复杂的和/或多元的。

来自https://angular.io/guide/router#optional-route-parameters

您只需要从路由路径中取出参数即可。

@RouteConfig([
{
    path: '/user/',
    component: User,
    as: 'User'
}])

6
更改可选的路由参数会重新渲染组件,但不会更改queryParams。同样,如果您在路线导航之前解析了一些数据,则每次更改可选的路线参数时都将要求它们。
Rakhat

1
仅供参考,该锚链接不再起作用。新的链接似乎是“ 路由参数”:是否必需?
spottedmahn

20

Angular 4-解决可选参数排序问题的解决方案:

做这个:

const appRoutes: Routes = [
  {path: '', component: HomeComponent},
  {path: 'products', component: ProductsComponent},
  {path: 'products/:id', component: ProductsComponent}
]

请注意,productsproducts/:id路由的命名完全相同。Angular 4将正确跟随products没有参数的路线,如果有参数,它将跟随products/:id

然而,对于非参数路由路径products必须不能有斜线,否则角度将错误地把它当作一个参数路径。因此,就我而言,我对产品使用尾随的斜线,但它不起作用。

请勿这样做:

...
{path: 'products/', component: ProductsComponent},
{path: 'products/:id', component: ProductsComponent},
...

如果两者都将转到ProductsComponent,则如何处理其中的可选参数?
Arwin

1
您可以像这样在ProductsComponent中访问:id1,:id2等参数以及所请求的url,例如:this.route.url.first().mergeMap((url)=> {// console.log('1:检测到url变化” + url);返回this.route.params.do((params)=> {// console.log('2:检测到url + params变化'+ params [“ id1”] +''+ params [“ id2”]); this.id1 = params [“ id1”]; this.id2 = params [“ id2”];})})
ObjectiveTC

2
请记住,您也可以传递data给组件,对于每个路由,即使传递给相同的组件,也可能有所不同。{path: 'products', component: ProductsComponent, data: { showAllProducts: true} },可以使用示例,然后检查showAllProducts。然后检查空值会更好一些,但是对于较简单的情况,两者都可以。
Simon_Weaver

1
不幸的是,该解决方案将阻止Angular在product和product /:id之间重用组件。该组件将被重新实例化。
科迪亚克

@Kodiak-我认为那是不对的。我的理解是,在app.module.ts中,ProductsComponent实例化了一次,然后角度引擎在每个可导航事件(products and products /:id等)上重用了实例化的ProductsComponent。您能否在上面的代码中解释或演示ProductsComponent如何重新实例化,以及如何防止重新实例化?
ObjectiveTC

11

rerezz的答案很不错,但是有一个严重的缺陷。它导致User组件重新运行ngOnInit方法。

从非参数路径切换到参数路径时,当您在其中做一些繁重的工作并且不希望重新运行时可能会出现问题。尽管这两个路由是要模仿一个可选的url参数,但不要成为2条单独的路由。

我建议您解决以下问题:

const routes = [
  {
    path: '/user',
    component: User,
    children: [
      { path: ':id', component: UserWithParam, name: 'Usernew' }
    ]
  }
];

然后,您可以将负责处理参数的逻辑移至UserWithParam组件,并将基本逻辑留在User组件中。User::ngOnInit/ user导航到/ user / 123时,您所做的任何操作都不会再次运行。

不要忘了把<router-outlet></router-outlet>User的模板。


如果性能至关重要,则避免重新创建组件是一件好事。我有另一个解决方案,它也避免了避免重新创建组件:stackoverflow.com/a/56391974/664533
Wayne Maurer,

4

这里的参考答案,包括接受的答案rerezz这表明添加多个路由条目做工精细。

但是,在路径条目之间进行更改时,即在带参数的路径条目与不带参数的条目之间进行更改时,将重新创建组件。

如果要避免这种情况,可以创建自己的路由匹配器,以匹配两个路由:

export function userPageMatcher(segments: UrlSegment[]): UrlMatchResult {
    if (segments.length > 0 && segments[0].path === 'user') {
        if (segments.length === 1) {
            return {
                consumed: segments,
                posParams: {},
            };
        }
        if (segments.length === 2) {
            return {
                consumed: segments,
                posParams: { id: segments[1] },
            };
        }
        return <UrlMatchResult>(null as any);
    }
    return <UrlMatchResult>(null as any);
 }

然后在路由配置中使用匹配器:

const routes: Routes = [
    {
        matcher: userPageMatcher,
        component: User,
    }
];

@KevinBeal我已经实现了很多与AOT配合使用的匹配器。您在这里遇到什么错误?
韦恩·莫勒

哎呀。那是另一回事。我的匹配器与AOT一起使用。
凯文·比尔19'Aug

这有点棘手,但是解决此问题的最佳方法
fedor.belov

4

使用angular4,我们只需要按层次结构一起组织路由

const appRoutes: Routes = [
  { 
    path: '', 
    component: MainPageComponent 
  },
  { 
    path: 'car/details', 
    component: CarDetailsComponent 
  },
  { 
    path: 'car/details/platforms-products', 
    component: CarProductsComponent 
  },
  { 
    path: 'car/details/:id', 
    component: CadDetailsComponent 
  },
  { 
    path: 'car/details/:id/platforms-products', 
    component: CarProductsComponent 
  }
];

这对我有用。这样,路由器会根据选项ID参数知道下一条路由。


1

遇到此问题的另一个实例,并在此寻求解决方案。我的问题是我在做孩子,并且延迟加载组件以及优化某些东西。简而言之,如果您懒于加载父模块。最主要的是我在路由中使用了“ /:id”,并且抱怨“ /”是其中的一部分。这里不是确切的问题,但适用。

来自父级的应用路由

...
const routes: Routes = [
  {
    path: '',
    children: [
      {
        path: 'pathOne',
        loadChildren: 'app/views/$MODULE_PATH.module#PathOneModule'
      },
      {
        path: 'pathTwo',
        loadChildren: 'app/views/$MODULE_PATH.module#PathTwoModule'
      },
...

子路由懒加载

...
const routes: Routes = [
  {
    path: '',
    children: [
      {
        path: '',
        component: OverviewComponent
      },
      {
        path: ':id',
        component: DetailedComponent
      },
    ]
  }
];
...


0

面对类似的延迟加载问题,我这样做:

const routes: Routes = [
  {
    path: 'users',
    redirectTo: 'users/',
    pathMatch: 'full'
  },
  {
    path: 'users',
    loadChildren: './users/users.module#UserssModule',
    runGuardsAndResolvers: 'always'
  },
[...]

然后在组件中:

  ngOnInit() {
    this.activatedRoute.paramMap.pipe(
      switchMap(
        (params: ParamMap) => {
          let id: string = params.get('id');
          if (id == "") {
            return of(undefined);
          }
          return this.usersService.getUser(Number(params.get('id')));
        }
      )
    ).subscribe(user => this.selectedUser = user);
  }

这条路:

  • 没有的路由/将重定向到使用的路由。由于的原因pathMatch: 'full',仅此类特定的完整路由被重定向。

  • 然后,users/:id被接收。如果实际路线为users/id则为"",请检查ngOnInit并采取相应措施;否则,id是ID并继续。

  • 其余部分所作用的对象是否selectedUser是未定义的(* ngIf和类似的东西)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.