Параметры маршрута и навигация
Параметр маршрута — изменяемая часть адреса. Для страницы статьи не нужно сто маршрутов: один маршрут posts/:id подходит к /posts/1, /posts/2 и так далее, а компонент получает номер статьи и загружает её.
Маршрут с параметром
ng generate component post-detail// src/app/app.routes.ts
import { Routes } from '@angular/router';
import { PostList } from './post-list/post-list';
import { PostDetail } from './post-detail/post-detail';
export const routes: Routes = [
{ path: 'posts', component: PostList },
{ path: 'posts/:id', component: PostDetail },
];Двоеточие отмечает параметр с именем id.
Ссылка с параметром
В списке статей заголовок станет ссылкой. Массив в routerLink собирает адрес из частей:
<!-- src/app/post-list/post-list.html -->
@for (post of posts(); track post.id) {
<h3><a [routerLink]="['/posts', post.id]">{{ post.title }}</a></h3>
}Добавьте RouterLink в imports компонента PostList. Ссылки ведут на /posts/1, /posts/2 и так далее.
Параметр как входное свойство
Самый простой способ получить параметр — включить привязку параметров к входам в app.config.ts:
// src/app/app.config.ts
provideRouter(routes, withComponentInputBinding()),Функцию withComponentInputBinding импортируйте из @angular/router. Теперь параметр id попадает во входное свойство с тем же именем:
// src/app/post-detail/post-detail.ts
import { Component, OnInit, inject, input, signal } from '@angular/core';
import { RouterLink } from '@angular/router';
import { PostApi } from '../post-api';
import { Post } from '../post';
@Component({
selector: 'app-post-detail',
imports: [RouterLink],
templateUrl: './post-detail.html',
})
export class PostDetail implements OnInit {
private api = inject(PostApi);
id = input.required<string>();
post = signal<Post | null>(null);
ngOnInit() {
this.api.getPost(Number(this.id())).subscribe((p) => this.post.set(p));
}
}<!-- src/app/post-detail/post-detail.html -->
<a routerLink="/posts">← Все статьи</a>
@if (post(); as p) {
<h2>{{ p.title }}</h2>
<p>{{ p.body }}</p>
} @else {
<p>Загрузка...</p>
}Щёлкните по заголовку в списке — откроется страница статьи. Параметры из адреса всегда строки, поэтому Number() превращает id в число.
Через ActivatedRoute
Без withComponentInputBinding параметр читают из сервиса ActivatedRoute:
// src/app/post-detail/post-detail.ts
private route = inject(ActivatedRoute);
ngOnInit() {
const id = Number(this.route.snapshot.paramMap.get('id'));
this.api.getPost(id).subscribe((p) => this.post.set(p));
}Так написано во многих старых примерах — результат тот же.
Переход из кода
Сервис Router переходит на другую страницу из метода — например, после сохранения формы:
// src/app/post-form/post-form.ts
private router = inject(Router);
save(title: string, body: string) {
this.api.createPost({ title, body }).subscribe(() => {
this.router.navigate(['/posts']);
});
}Метод navigate() принимает такой же массив, как routerLink, например ['/posts', 5]. Есть и navigateByUrl('/posts') для готовой строки.
Частая ошибка
При переходе с /posts/1 на /posts/2 Angular не создаёт компонент заново, а переиспользует его — ngOnInit второй раз не вызывается, и на странице остаётся старая статья. Если такие переходы возможны (например, ссылка «Следующая статья»), загружайте данные в effect(), который читает this.id(): он сработает при каждом новом значении параметра.