Как работают маршруты с параметрами (Route Parameters)?

В Angular маршруты с параметрами (Route Parameters) позволяют передавать данные в маршруты через URL-адрес. Это полезно для динамической навигации, например: просмотр страницы пользователя по его ID, открытие поста по slug, отображение деталей товара и т.д. Angular предоставляет инструменты для определения маршрутов с параметрами, извлечения их значений и реагирования на их изменения.

1. Определение маршрута с параметрами

В файле маршрутизации (app-routing.module.ts) параметры определяются с помощью двоеточия (:):

const routes: Routes = \[
{ path: 'user/:id', component: UserComponent },
{ path: 'post/:slug', component: PostComponent }
\];

В этом примере:

  • user/:id — параметр id динамический.

  • post/:slug — параметр slug динамический.

URL example.com/user/42 вызовет компонент UserComponent с параметром id = 42.

2. Навигация с параметрами

Маршруты с параметрами можно активировать двумя способами:

Через ссылку в шаблоне

<a \[routerLink\]="\['/user', user.id\]">Профиль</a>

Это навигация к маршруту user/123, если user.id = 123.

Через Router программно

constructor(private router: Router) {}
goToUserProfile(id: number) {
this.router.navigate(\['/user', id\]);
}

3. Получение параметров в компоненте

Angular предоставляет два основных способа получения параметров маршрута:

Через ActivatedRoute.snapshot

Если параметры не будут меняться после инициализации компонента (например, при первой загрузке), можно использовать snapshot:

constructor(private route: ActivatedRoute) {}
ngOnInit() {
const userId = this.route.snapshot.paramMap.get('id');
}

paramMap.get('id') возвращает значение параметра id в виде строки (или null).

Через ActivatedRoute.params (Observable)

Если маршрут может измениться, пока компонент жив (например, если он не уничтожается при переходе на другую страницу с другим параметром), нужно подписаться на params:

this.route.params.subscribe(params => {
const id = params\['id'\];
});

Важно отписываться от этой подписки при уничтожении компонента, чтобы избежать утечек памяти.

Пример с ngOnDestroy:

subscription!: Subscription;
ngOnInit() {
this.subscription = this.route.params.subscribe(params => {
this.userId = params\['id'\];
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}

4. Несколько параметров в маршруте

Можно указать несколько параметров:

{ path: 'category/:categoryId/product/:productId', component: ProductComponent }

Путь category/12/product/55 создаст:

  • categoryId = 12

  • productId = 55

Получение в компоненте:

this.route.params.subscribe(params => {
const categoryId = params\['categoryId'\];
const productId = params\['productId'\];
});

5. Query Parameters (параметры запроса)

Это параметры, добавляемые к URL после ?, не входящие в путь маршрута:

Пример URL: /products?page=2&sort=asc

Чтение:

this.route.queryParamMap.subscribe(queryParams => {
const page = queryParams.get('page');
const sort = queryParams.get('sort');
});

Программная установка:

this.router.navigate(\['/products'\], { queryParams: { page: 2, sort: 'asc' } });

6. Обработка изменений параметров маршрута

Если пользователь переходит с /user/1 на /user/2, Angular может не пересоздать компонент UserComponent (если он уже активен), а просто изменит параметры. Поэтому следует всегда подписываться на params, чтобы реагировать на изменения.

this.route.params.subscribe(params => {
this.loadUser(params\['id'\]);
});

7. Использование ActivatedRoute в дочерних маршрутах

Если компонент вложен и параметры задаются на уровне родителя:

const routes: Routes = \[
{
path: 'user/:id',
component: UserComponent,
children: \[
{ path: 'profile', component: ProfileComponent }
\]
}
\];

Чтобы получить параметр id в дочернем компоненте (ProfileComponent), используйте parent:

this.route.parent?.params.subscribe(params => {
const userId = params\['id'\];
});

8. Route Resolvers (предзагрузка данных)

Если нужно получить данные по параметру до активации компонента, используйте resolve.

{
path: 'user/:id',
component: UserComponent,
resolve: {
user: UserResolver
}
}

Реализация UserResolver:

@Injectable({ providedIn: 'root' })
export class UserResolver implements Resolve<User> {
constructor(private userService: UserService) {}
resolve(route: ActivatedRouteSnapshot): Observable<User> {
const id = route.paramMap.get('id')!;
return this.userService.getUserById(+id);
}
}

В компоненте доступ к данным:

ngOnInit() {
this.route.data.subscribe(data => {
this.user = data\['user'\];
});
}

9. Пример полного цикла

Роутинг:

{ path: 'order/:orderId', component: OrderDetailComponent }

Шаблон:

<a \[routerLink\]="\['/order', order.id\]">Посмотреть заказ</a>

Компонент:

export class OrderDetailComponent implements OnInit {
orderId!: string;
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.route.params.subscribe(params => {
this.orderId = params\['orderId'\];
this.fetchOrderDetails();
});
}
fetchOrderDetails() {
// Запрос на сервер по orderId
}
}

Параметры маршрута — мощный механизм, позволяющий динамически управлять навигацией и данными в Angular-приложениях. Они обеспечивают простую интеграцию с URL, что важно как для UX, так и для SEO.