简体   繁体   English

Angular 2 可选路由参数

[英]Angular 2 optional route parameter

Is it possible to have an optional route parameter in the Angular 2 route?在 Angular 2 路由中是否可以有一个可选的路由参数? I tried the Angular 1.x syntax in RouteConfig but received below error:我在 RouteConfig 中尝试了 Angular 1.x 语法,但收到以下错误:

"ORIGINAL EXCEPTION: Path "/user/:id?" contains "?" which is not allowed in a route config." “原始异常:路径“/user/:id?”包含“?”,这在路由配置中是不允许的。”

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

You can define multiple routes with and without parameter:您可以使用和不使用参数定义多个路由:

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

and handle the optional parameter in your component:并处理组件中的可选参数:

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

    if (paramId) {
        ...
    }
}

See also the related github issue: https://github.com/angular/angular/issues/3525另请参阅相关的 github 问题: https : //github.com/angular/angular/issues/3525

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

This way the component isn't re-rendered when the parameter is added.这样,当添加参数时组件不会重新渲染。

It's recommended to use a query parameter when the information is optional.当信息是可选的时,建议使用查询参数。

Route Parameters or Query Parameters?路由参数还是查询参数?

There is no hard-and-fast rule.没有硬性规定。 In general,一般来说,

prefer a route parameter when更喜欢路由参数时

  • the value is required.该值是必需的。
  • the value is necessary to distinguish one route path from another.该值对于区分一条路由路径和另一条路由路径是必要的。

prefer a query parameter when更喜欢查询参数时

  • the value is optional.该值是可选的。
  • the value is complex and/or multi-variate.该值是复杂的和/或多变量的。

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

You just need to take out the parameter from the route path.您只需要从路由路径中取出参数即可。

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

Angular 4 - Solution to address the ordering of the optional parameter: Angular 4 - 解决可选参数排序的解决方案:

DO THIS:做这个:

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

Note that the products and products/:id routes are named exactly the same.请注意, productsproducts/:id路由的名称完全相同。 Angular 4 will correctly follow products for routes with no parameter, and if a parameter it will follow products/:id . Angular 4 将正确跟踪没有参数的路由的products ,如果有参数,它将遵循products/:id

However, the path for the non-parameter route products must not have a trailing slash, otherwise angular will incorrectly treat it as a parameter-path.但是,非参数路由products的路径不能有尾部斜杠,否则 angular 会错误地将其视为参数路径。 So in my case, I had the trailing slash for products and it wasn't working.所以就我而言,我有产品的尾随斜线,但它不起作用。

DON'T DO THIS:不要这样做:

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

rerezz's answer is pretty nice but it has one serious flaw. rerezz 的回答非常好,但它有一个严重的缺陷。 It causes User component to re-run the ngOnInit method.它会导致User组件重新运行ngOnInit方法。

It might be problematic when you do some heavy stuff there and don't want it to be re-run when you switch from the non-parametric route to the parametric one.当您在那里执行一些繁重的工作并且在从非参数路由切换到参数路由时不希望它重新运行时,这可能会出现问题。 Though those two routes are meant to imitate an optional url parameter, not become 2 separate routes.尽管这两条路由旨在模仿可选的 url 参数,但不会成为 2 条独立的路由。

Here's what I suggest to solve the problem:以下是我解决问题的建议:

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

Then you can move the logic responsible for handling the param to the UserWithParam component and leave the base logic in the User component.然后,您可以将负责处理参数的逻辑移至UserWithParam组件,而将基本逻辑留在User组件中。 Whatever you do in User::ngOnInit won't be run again when you navigate from /user to /user/123 .当您从/user导航到/user/123时,无论您在User::ngOnInit做什么都不会再次运行。

Don't forget to put the <router-outlet></router-outlet> in the User 's template.不要忘记将<router-outlet></router-outlet>放在User的模板中。

The suggested answers here, including the accepted answer from rerezz which suggest adding multiple route entries work fine.此处建议的答案,包括rerezz接受的答案,建议添加多个路由条目工作正常。

However the component will be recreated when changing between the route entries, ie between the route entry with the parameter and the entry without the parameter.然而,当在路由条目之间,即在带有参数的路由条目和没有参数的条目之间进行更改时,将重新创建组件。

If you want to avoid this, you can create your own route matcher which will match both routes:如果你想避免这种情况,你可以创建自己的路由匹配器来匹配两条路由:

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);
 }

Then use the matcher in your route config:然后在路由配置中使用匹配器:

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

With angular4 we just need to organise routes together in hierarchy使用 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 
  }
];

This works for me .这对我有用。 This way router know what is the next route based on option id parameters.这样路由器就可以根据选项 id 参数知道下一条路由是什么。

There are three ways to send route parameter(s) from one component to other component through routes.有三种方法可以通过路由将路由参数从一个组件发送到另一个组件。 But first import these libraries in components related.ts files and define in constructor但首先将这些库导入组件 related.ts 文件并在构造函数中定义

private route: ActivatedRoute
private router: Router

1st Way: Required routing parameters第一种方式:必需的路由参数

//Route Configuration
{path: 'user/:id', component: UserDetailComponent}

//Set Hyperlink/routerLink
<a [routerLink]="['/user', user.id]"></a> 

 //Requesting Url after click on hyperlink
 http://localhost:4200/user/6

//Now you can read id value in navigated component
this.route.snapshot.paramMap.get('id');

2nd Way: Optional path parameters第二种方式:可选路径参数

//Route Configuration
    {path: 'user', component: UserDetailComponent}
    
    //Set Hyperlink/routerLink
    <a [routerLink]=['/user', {name: userName, status: true}]"></a>


//Requesting Url after click on hyperlink
    http://localhost:4200/user;name:userNameValue;status:true

//Now you can read values in navigated component
    this.route.snapshot.paramMap.get('userId');
    this.route.snapshot.paramMap.get('userName');

3rd Way: Optional path parameters第三种方式:可选路径参数

//Route Configuration
    {path: 'user', component: UserDetailComponent}
    
    //Set Hyperlink/routerLink
    <a [routerLink]="['/user']"  [queryParms]="{userId:'911', status:true}"></a>

    //Requesting Url after click on hyperlink
    http://localhost:4200/user?userId=911&status=true

    
    //Now you can read values in navigated component
    this.route.snapshot.paramMap.get('userId');
    this.route.snapshot.paramMap.get('userName');

Reference: https://qastack.mx/programming/44864303/send-data-through-routing-paths-in-angular参考: https://qastack.mx/programming/44864303/send-data-through-routing-paths-in-angular

Ran into another instance of this problem, and in searching for a solution to it came here.遇到此问题的另一个实例,并在寻找解决方案时来到这里。 My issue was that I was doing the children, and lazy loading of the components as well to optimize things a bit.我的问题是我正在做孩子,以及组件的延迟加载以优化一些东西。 In short if you are lazy loading the parent module.简而言之,如果您懒惰加载父模块。 Main thing was my using '/:id' in the route, and it's complaints about '/' being a part of it.主要是我在路由中使用了 '/:id',它抱怨 '/' 是它的一部分。 Not the exact problem here, but it applies.不是这里的确切问题,但它适用。

App-routing from parent来自父级的应用程序路由

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

Child routes lazy loaded子路由懒加载

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

With this matcher function you can get desirable behavior without component re-rendering.使用此匹配器功能,您无需重新渲染组件即可获得理想的行为。 When url.length equals to 0, there's no optional parameters, with url.length equals to 1, there's 1 optional parameter.当 url.length 等于 0 时,没有可选参数,当 url.length 等于 1 时,有 1 个可选参数。 id - is the name of optional parameter. id - 是可选参数的名称。

  const routes: Routes = [
  {
    matcher: (segments) => {
      if (segments.length <= 1) {
        return {
          consumed: segments,
          posParams: {
            id: new UrlSegment(segments[0]?.path || '', {}),
          },
        };
      }
      return null;
    },
    pathMatch: 'prefix',
    component: UserComponent,
  }]

In Angular 8, ou can simply add the parameter without changing your router config.在 Angular 8 中,您可以简单地添加参数而无需更改您的路由器配置。

Angular Doc Optional param Angular Doc 可选参数

In yourModule.routing.module.ts在 yourModule.routing.module.ts

const routes: Routes = [
  { path: 'somePath/:RequiredParam', component: Yourcomponent }
];

In your template :在您的模板中:

<div [RouterLink] = ['somePath', requiredParamValue, {optionalParam: value}]></div>

I can't comment, but in reference to: Angular 2 optional route parameter我无法评论,但参考: Angular 2 optional route parameter

an update for Angular 6: Angular 6 的更新:

import {map} from "rxjs/operators"

constructor(route: ActivatedRoute) {
  let paramId = route.params.pipe(map(p => p.id));

  if (paramId) {
    ...
  }
}

See https://angular.io/api/router/ActivatedRoute for additional information on Angular6 routing.有关 Angular6 路由的其他信息,请参阅https://angular.io/api/router/ActivatedRoute

Facing a similar problem with lazy loading I have done this:面对与延迟加载类似的问题,我已经这样做了:

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

And then in the component:然后在组件中:

  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);
  }

This way:这边走:

  • The route without / is redirected to the route with.没有/的路由被重定向到有的路由。 Because of the pathMatch: 'full' , only such specific full route is redirected.由于pathMatch: 'full' ,只有这样的特定完整路由被重定向。

  • Then, users/:id is received.然后,接收到users/:id If the actual route was users/ , id is "" , so check it in ngOnInit and act accordingly;如果实际路由是users/id"" ,所以在ngOnInit检查它并采取相应的行动; else, id is the id and proceed.否则, id是 id 并继续。

  • The rest of the componect acts on selectedUser is or not undefined (*ngIf and the things like that).作用于selectedUser的其余组件是否未定义(*ngIf 和类似的东西)。

Had the same issue with a Master Detail view. Master Detail 视图也有同样的问题。 The master view can be visible without the :elementId parameter, but should still be displayed with detail selection open and with the :elementId in the url.主视图可以在没有:elementId参数的情况下可见,但仍应在打开详细信息选择并在 url 中使用:elementId时显示。

I solved it as follows:我是这样解决的:

const routes: Routes = [
  {
    path: '',
    component: MasterDetailComponent,
    children: [
      {
        path: ':elementId',
        children: [
          {
            path: 'details',
            component: DetailComponent
          },
          {
            path: '',
            redirectTo: 'details'
          }
        ]
      }
    ]
  }
];

Then in MasterDetailComponent (eg in ngOnInit method) you can get the :elementId using the child route:然后在 MasterDetailComponent (例如在 ngOnInit 方法中)您可以使用子路由获取:elementId

const childRouteWithElementId = this.route.snapshot.children[0];
const elementIdFromUrl = childRouteWithElementId.params.elementId;
if (!!elementIdFromUrl ) {
  // Do what you need to with the optional parameter
}

Of course you could do the same thing without the child routes and only have the optional elementId at the end of the url.当然,您可以在没有子路由的情况下做同样的事情,并且在 url 末尾只有可选的elementId

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM