Angular 2 необязательных параметра маршрута

Возможно ли иметь необязательный параметр маршрута в маршруте Angular 2? Я пробовал синтаксис Angular 1.x в RouteConfig, но получил ошибку ниже:

"ORIGINAL EXCEPTION: Path" /user/: id? "содержит"? ", который не разрешен в конфигурации маршрута."

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

Ответ 1

Вы можете определить несколько маршрутов с параметром и без него:

@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

Ответ 2

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

Таким образом, компонент не перерисовывается при добавлении параметра.

Ответ 3

Рекомендуется использовать параметр запроса, когда информация является необязательной.

Параметры маршрута или параметры запроса?

Здесь нет строгих правил. В общем,

предпочитают параметр маршрута, когда

  • значение обязательно.
  • значение необходимо, чтобы отличить один маршрут от другого.

предпочитаю параметр запроса, когда

  • значение необязательно.
  • значение является сложным и/или многовариантным.

из https://angular.io/guide/router#optional-route-parameters

Вам просто нужно вынуть параметр из пути маршрута.

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

Ответ 4

Angular 4 - Решение для адресации необязательного параметра:

ДЕЛАТЬ ЭТО:

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

Обратите внимание, что маршруты products и products/:id называются точно такими же. Angular 4 будет правильно следовать products для маршрутов без параметра, а если параметр будет следовать products/:id.

Однако путь для непараметрического маршрута products не должен иметь завершающую косую черту, иначе Angular будет неправильно рассматривать его как путь к параметру. Так что в моем случае у меня был конечный слэш для продуктов, и он не работал.

НЕ ДЕЛАЙТЕ ЭТО:

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

Ответ 5

Ответ rerezz довольно хорош, но у него есть один серьезный недостаток. Это заставляет User компонент повторно запускать метод ngOnInit.

Это может быть проблематично, когда вы выполняете какие-то тяжелые операции и не хотите, чтобы они запускались повторно при переключении с непараметрического маршрута на параметрический. Хотя эти два маршрута предназначены для имитации необязательного параметра url, они не становятся двумя отдельными маршрутами.

Вот что я предлагаю для решения проблемы:

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

Затем вы можете переместить логику, отвечающую за обработку параметра, в компонент UserWithParam и оставить базовую логику в компоненте User. Все, что вы делаете в User::ngOnInit больше не будет выполняться при User::ngOnInit от /user к /user/123.

Не забудьте поместить <router-outlet></router-outlet> в шаблон User.

Ответ 6

С угловым4 нам просто нужно организовать маршруты вместе в иерархии

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

Это работает для меня. Таким образом, маршрутизатор знает, какой следующий маршрут основан на параметрах идентификатора параметра.

Ответ 7

Перейдите в другой экземпляр этой проблемы, и в поисках решения к нему пришли сюда. Моя проблема заключалась в том, что я делал детей, и ленивая загрузка компонентов, а также для оптимизации вещей. Короче, если вы ленивы загружаете родительский модуль. Главное было использовать "/: 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
      },
    ]
  }
];
...

Ответ 8

Предлагаемые ответы здесь, включая принятый ответ от 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);
 }

Затем используйте matcher в вашей конфигурации маршрута:

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

Ответ 9

Я не могу комментировать, но в отношении: Angular 2 необязательный параметр маршрута

обновление для Angular 6:

import {map} from "rxjs/operators"

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

  if (paramId) {
    ...
  }
}

См. Https://angular.io/api/router/ActivationRoute для получения дополнительной информации о маршрутизации Angular6.

Ответ 10

Столкнувшись с аналогичной проблемой с отложенной загрузкой, я сделал это:

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 - это идентификатор и продолжить.

  • Остальная часть компонента действует на selectedUser или не определена (* ngIf и тому подобное).