Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Параметры маршрута и навигация

Параметр маршрута — изменяемая часть адреса. Для страницы статьи не нужно сто маршрутов: один маршрут 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(): он сработает при каждом новом значении параметра.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.