Как передать данные в компонент Angular при маршрутизации?
Основные способы передачи данных в Angular при маршрутизации
В Angular существует несколько проверенных способов передачи данных в компонент при маршрутизации. Рассмотрим основные подходы, начиная с самого простого и заканчивая более продвинутыми.
1. Параметры маршрута (Route Parameters) — самый распространенный способ
Используйте динамические сегменты в пути маршрута, как вы уже начали делать с :id. В компоненте-получателе получите параметры через сервис ActivatedRoute.
// user-detail.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { switchMap } from 'rxjs/operators';
import { UserService } from './user.service';
@Component({
selector: 'app-user-detail',
template: '<div>User {{ userId }}: {{ user?.name }}</div>'
})
export class UserDetailComponent implements OnInit {
userId: number;
user: any;
constructor(
private route: ActivatedRoute,
private userService: UserService
) {}
ngOnInit() {
// Получаем параметр id из маршрута
this.route.paramMap.subscribe(params => {
this.userId = Number(params.get('id'));
this.loadUser();
});
// Более продвинутый вариант с RxJS (рекомендуется)
this.route.paramMap.pipe(
switchMap(params => {
this.userId = Number(params.get('id'));
return this.userService.getUser(this.userId);
})
).subscribe(user => this.user = user);
}
loadUser() {
// Загрузка данных пользователя по ID
this.user = this.userService.getUser(this.userId);
}
}
2. Query Parameters (параметры запроса)
Подходит для необязательных данных, которые не влияют на структуру маршрута (например, фильтры, настройки отображения).
// Передача
this.router.navigate(['/users'], {
queryParams: { page: 2, sort: 'name' }
});
// Получение в компоненте
this.route.queryParamMap.subscribe(params => {
const page = params.get('page');
const sort = params.get('sort');
});
3. Данные через сервис (Service Data Sharing)
Лучший вариант для сложных данных или когда нужно сохранить состояние между переходами. Создайте сервис с BehaviorSubject для хранения данных.
// data-sharing.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class DataSharingService {
private userDataSubject = new BehaviorSubject<any>(null);
userData$ = this.userDataSubject.asObservable();
setUserData(data: any) {
this.userDataSubject.next(data);
}
}
// user-list.component.ts (передача)
this.dataSharing.setUserData({ id: 1, name: 'Alice' });
this.router.navigate(['/users/detail']);
// user-detail.component.ts (получение)
this.dataSharing.userData$.subscribe(data => {
if (data) this.user = data;
});
4. State (состояние навигации) — для временных данных
Можно передать объект через свойство state при навигации. Данные не видны в URL.
// Передача
this.router.navigate(['/users/detail'], {
state: { userData: { id: 1, name: 'Alice' } }
});
// Получение
constructor(private router: Router) {
const navigation = this.router.getCurrentNavigation();
if (navigation?.extras?.state) {
const userData = navigation.extras.state['userData'];
}
}
Рекомендации по выбору метода
- Параметры маршрута — для обязательных идентификаторов (ID, slug). Данные видны в URL, что позволяет делать прямые ссылки.
- Query parameters — для необязательных параметров (фильтры, страницы).
- Сервис с BehaviorSubject — для сложных объектов или когда нужно сохранить данные между переходами.
- State — для временных данных, которые не должны быть в URL и не нужны после перехода.
В вашем случае с ID пользователя лучше всего подходит первый вариант — параметры маршрута. Используйте ActivatedRoute.paramMap и не забудьте преобразовать строку в число с помощью Number() или оператора +.
Альтернативный подход: Resolver для предзагрузки данных
Если вам нужно не просто передать ID, а сразу получить данные пользователя перед активацией маршрута, используйте Angular Resolver. Это сервис, который загружает данные до того, как компонент будет создан.
// user-resolver.service.ts
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
import { UserService } from './user.service';
@Injectable({ providedIn: 'root' })
export class UserResolver implements Resolve<any> {
constructor(private userService: UserService) {}
resolve(route: ActivatedRouteSnapshot) {
const id = Number(route.paramMap.get('id'));
return this.userService.getUser(id);
}
}
// app-routing.module.ts
const routes: Routes = [
{
path: 'users/:id',
component: UserDetailComponent,
resolve: { user: UserResolver } // Данные будут доступны как 'user'
}
];
// user-detail.component.ts
export class UserDetailComponent implements OnInit {
user: any;
constructor(private route: ActivatedRoute) {}
ngOnInit() {
// Данные уже загружены Resolver'ом
this.route.data.subscribe(data => {
this.user = data['user'];
});
}
}
Преимущество Resolver в том, что компонент гарантированно получит данные (или маршрут не активируется при ошибке). Это упрощает код компонента и улучшает пользовательский опыт — нет состояния загрузки внутри компонента. Однако будьте осторожны: Resolver блокирует навигацию до завершения загрузки, поэтому для медленных запросов лучше использовать загрузчик в компоненте.