Кутовий 2 необов'язковий параметр маршруту


180

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

"ОРИГІНАЛЬНЕ ВИКОНАННЯ: Шлях" / 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/isissue/3525


11
Виправте мене, якщо я помиляюся, але це рішення спрацювало для мене лише тоді, коли порядок маршрутів у масиві був змінений, тобто маршрут з параметром відбувся до іншого. Поки я цього не зробив, маршрутизатор відповідав лише маршруту без параметра.
Авіад П.

10
чи все ще застосовується це рішення? Я помітив, що перехід від "Користувача" до "UserNew" відновить компонент "Користувач"
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прочитайте "всі" або "додому" як idі просто ігноруйте його, якщо воно відповідає вашому магічному значенню. Тоді перший рядок стає, redirectTo: 'users/home'або все, що ви вирішите. Для мене кінець косої риси дійсно виділяється як щось не так.
Simon_Weaver

@Simon_Weaver Я згоден. Я знайшов інше рішення за допомогою матчера, у якого немає цієї проблеми: stackoverflow.com/a/56391974/664533
Wayne Maurer

1
це просто заклинання, але досить непорушне: D Найкраще рішення!
Веррі

45

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

Параметри маршруту чи параметри запиту?

Не існує жорсткого правила. В загальному,

віддайте перевагу параметру маршруту, коли

  • значення обов'язкове.
  • значення необхідно для того, щоб відрізнити один шлях маршруту від іншого.

віддайте перевагу параметру запиту, коли

  • значення необов’язкове.
  • значення є складним та / або багато змінним.

від https://angular.io/guide/router#optional-route-parameters

Вам просто потрібно вийняти параметр з маршруту маршруту.

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

6
Зміна опціональних парам маршрутів відображає компоненти, але зміна queryParams не робить. Також якщо ви вирішите деякі дані перед навігацією по маршруту, вона буде запитуватися щоразу, коли ви змінюєте необов'язкові параметри маршруту.
Рахат

1
FYI, ця прив'язка більше не працює. Здається, що нове посилання є Параметри маршруту: Обов’язкове чи необов’язкове?
spottedmahn

20

Кутова 4 - Рішення для впорядкування необов'язкового параметра:

ЗРОБИТИ ЦЕ:

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

Зауважте, що productsі products/:idмаршрути названі абсолютно однаково. Кутовий 4 буде правильно слідувати productsдля маршрутів без параметра, а якщо параметр - він буде products/:id.

Однак шлях для непараметричного маршруту неproducts повинен мати косою косою рисою, інакше кутова неправильно трактуватиме його як шлях параметра. Тож у моєму випадку у мене з'явилася остання коса риса для продуктів, і вона не працювала.

НЕ робіть цього:

...
{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 ((парами) => {// console.log (' 2: виявлено зміну URL-адреси та парам-файлів '+ 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 при кожному події, що переміщується (продукти та продукти /: id тощо). Чи можете ви пояснити чи продемонструвати, як 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шаблон 's.


Уникати відтворення компонента - це добре, якщо продуктивність є критичною. У мене є ще одне рішення, яке також дозволяє уникнути відтворення компонента: 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.
Кевін Біл

це трохи хитро, але найкраще рішення цієї проблеми
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

Я не можу коментувати, але посилаючись на: Кутовий 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/ActivateRoute для отримання додаткової інформації про маршрутизацію 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.