Угловой 2 необязательный параметр маршрута


180

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

«ORIGINAL EXCEPTION: Path» / user /: id? »Содержит«? », Что не разрешено в конфигурации маршрута.»

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

Ответы:


298

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

@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
Поправьте меня, если я ошибаюсь, но это решение сработало для меня только тогда, когда порядок маршрутов в массиве был изменен, т.е. маршрут с параметром произошел раньше другого. Пока я не сделал это, маршрутизатор соответствовал только маршруту без параметра.
Авиад П.

10
это решение все еще применяется? Я заметил, что при переходе от «User» к «UserNew» будет создан экземпляр компонента «User»
teleaziz

19
Старая, но главная проблема этого подхода заключается в том, что каждый маршрут рассматривается как уникальный маршрут, и это делает невозможным повторное использование компонента.
Агония

4
Как отмечает @teleaziz, добавление параметра приведет к повторной визуализации компонента. Чтобы избежать этого, ответ Мартина Кремера; добавление корня 'redirectTo' с пустым значением параметра мне очень помогло : stackoverflow.com/a/49159166/1364650 - но это довольно странно, я думаю, что они должны просто правильно поддерживать необязательные параметры маршрута.
Винсент Селс

2
Для тех, кто интересуется, почему RouteParamsне импортировать в компонент, проверьте это: stackoverflow.com/a/36792261/806202 . Решение заключается в использовании ActivatedRoute:route.snapshot.params['routeParam']
Арсен Хачатурян

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

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


6
Этот ответ самый лучший. Он не рендерит один и тот же компонент и не требует нескольких компонентов.
Рекс,

4
Лучший ответ, но я добавил pathMatch: 'full'для перенаправления, в противном случае пути, такие как users/admin, также перенаправлены в моем случае
Валерий Катков

4
Этот ответ является лучшим, если вы согласны с косой чертой в URL-адресах при просмотре в браузере. Подумайте, может быть, о значении, которое представляет «неопределенный идентификатор», например, /users/allили /users/home, прочитайте «all» или «home» как « idи» и просто игнорируйте его, если оно соответствует вашему магическому значению. Затем первая строка выше становится redirectTo: 'users/home'или как вы решите. Для меня косая черта действительно выделяется, как что-то не так.
Simon_Weaver

@Simon_Waaver Я согласен. Я нашел другое решение, используя средство сравнения, у которого нет этой проблемы: 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 - нет. Также, если вы разрешите некоторые данные перед навигацией по маршруту, они будут запрашиваться каждый раз при изменении дополнительных параметров маршрута.
Рахат

1
К вашему сведению, эта якорная ссылка больше не работает. Новая ссылка выглядит как Route Parameters: Обязательный или необязательный?
spottedmahn

20

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},
...

Если оба идут в ProductsComponent, как вы справляетесь с необязательным параметром там?
Арвин

1
Вы можете получить доступ к параметрам: id1,: id2 и т. Д., А также к запрошенному URL-адресу в ProductsComponent, например: 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 повторно использовать компонент между продуктами и продуктами /: id. Компонент будет повторно создан.
Кадьяк

@Kodiak - я не верю, что это правильно. Насколько я понимаю, в app.module.ts один раз создается экземпляр ProductsComponent, а затем угловой механизм повторно использует этот экземпляр экземпляра ProductsComponent при каждом перемещаемом событии (products и products /: id и т. Д.). Можете ли вы объяснить или продемонстрировать, как ProductsComponent может быть повторно создан в приведенном выше коде, и как вы будете действовать для предотвращения повторного создания экземпляра?
ObjectiveTC

11

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

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

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

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шаблоне «S.


Избегать воссоздания компонента - это хорошо, если производительность критична. У меня есть другое решение, которое также позволяет избежать повторного создания компонента: stackoverflow.com/a/56391974/664533
Уэйн Маурер

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

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

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

@KevinBeal Я реализовал довольно много соответствий, которые работают с AOT. Какую ошибку вы получаете здесь?
Уэйн Маурер

К сожалению. Это было что-то еще. Мой matcher работает с AOT.
Кевин Бил

это немного сложно, но лучшее решение этой проблемы
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 
  }
];

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


1

Наткнулся на еще один экземпляр этой проблемы, и в поисках ее решения пришел сюда. Моя проблема заключалась в том, что я занимался детьми и ленивой загрузкой компонентов, чтобы немного оптимизировать вещи. Короче если вам лень загружать родительский модуль. Главное, что я использовал «/: id» в маршруте, и это жалобы на то, что «/» является его частью. Не точная проблема здесь, но это относится.

App-маршрутизация от родителя

...
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

Я не могу комментировать, но в отношении: 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.


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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.