Передача данных в Angular routed components: 5 лучших способов

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Как передать данные в Angular routed components: полное руководство на TypeScript

Каждый разработчик, который начинает работать с Angular, рано или поздно сталкивается с вопросом: «Как передать данные из одного компонента в другой через роутер?». На Stack Overflow этот вопрос собрал тысячи просмотров — и это не случайно. В отличие от обычных parent-child компонентов, где достаточно использовать @Input() и @Output(), роутинг в Angular добавляет свои сложности.

В этой статье мы разберём 5 проверенных способов передачи данных в Angular routed components. Вы узнаете, когда какой метод использовать, и получите готовые примеры на TypeScript. Поехали!

Почему нельзя просто передать данные через @Input?

Многие новички пытаются сделать так:

// ❌ Так не работает
<router-outlet [someData]="data"></router-outlet>

Angular Router создаёт компоненты динамически. router-outlet — это директива, а не шаблонный элемент. Поэтому передача данных напрямую через атрибуты невозможна. Но есть обходные пути — и они даже удобнее!

Способ 1: Использование Router State (самый простой)

Самый интуитивный способ — передать данные через объект state при навигации. Этот метод появился в Angular 7+ и работает «из коробки».

Как это работает

Вы передаёте объект с данными при вызове router.navigate() или через routerLink.

// Component A — отправитель
import { Component } from '@angular/core';
import { Router } from '@angular/router';

@Component({
  selector: 'app-user-list',
  template: `
    <button (click)="goToDetails()">Открыть пользователя</button>
  `
})
export class UserListComponent {
  constructor(private router: Router) {}

  goToDetails() {
    this.router.navigate(['/user', 42], {
      state: { name: 'Иван Петров', role: 'admin' }
    });
  }
}
// Component B — получатель
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

@Component({
  selector: 'app-user-details',
  template: `
    <div *ngIf="userData">
      <h2>{{ userData.name }}</h2>
      <p>Роль: {{ userData.role }}</p>
    </div>
  `
})
export class UserDetailsComponent implements OnInit {
  userData: any;

  constructor(private router: Router) {
    // Получаем данные из истории навигации
    this.userData = this.router.getCurrentNavigation()?.extras?.state;
  }

  ngOnInit() {
    // Альтернативный способ — через history.state
    if (!this.userData) {
      this.userData = history.state;
    }
  }
}

Плюсы и минусы

  • ✅ Простота реализации
  • ✅ Данные не видны в URL
  • ✅ Работает с любыми типами данных (объекты, массивы)
  • ❌ Данные теряются при обновлении страницы
  • ❌ Не работает при прямом переходе по URL

Когда использовать: для передачи временных данных, которые не критичны при перезагрузке (например, flash-сообщения, фильтры).

Способ 2: Route Resolver (для предзагрузки данных)

Если вам нужно загрузить данные до того, как компонент отобразится, используйте Angular Resolver. Это сервис, который резолвит данные перед активацией маршрута.

Создаём Resolver

// user.resolver.ts
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
import { Observable, of } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class UserResolver implements Resolve<any> {
  resolve(route: ActivatedRouteSnapshot): Observable<any> {
    const userId = route.paramMap.get('id');
    // Имитация HTTP-запроса
    return of({
      id: userId,
      name: 'Мария Соколова',
      email: 'maria@example.com'
    });
  }
}

Настройка маршрута

// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { UserDetailsComponent } from './user-details/user-details.component';
import { UserResolver } from './resolvers/user.resolver';

const routes: Routes = [
  {
    path: 'user/:id',
    component: UserDetailsComponent,
    resolve: { userData: UserResolver }
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Получение данных в компоненте

// user-details.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-user-details',
  template: `
    <h2>{{ user?.name }}</h2>
    <p>Email: {{ user?.email }}</p>
  `
})
export class UserDetailsComponent implements OnInit {
  user: any;

  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    this.user = this.route.snapshot.data['userData'];
    // Или подписка на изменения:
    // this.route.data.subscribe(data => this.user = data['userData']);
  }
}

Плюсы и минусы

  • ✅ Данные загружаются до рендера компонента
  • ✅ Легко тестировать и переиспользовать
  • ✅ Работает при прямом переходе по URL
  • ❌ Требуется больше кода (отдельный сервис)
  • ❌ Избыточно для простых данных

Когда использовать: когда компоненту нужны данные с сервера перед отображением (профиль пользователя, детали товара).

Способ 3: Query Parameters и Fragment (данные в URL)

Самый «веб-способ» — передавать данные через query-параметры (?key=value) или фрагменты (#section). Данные видны в URL, что удобно для шаринга.

Пример с query params

// Отправитель
this.router.navigate(['/search'], {
  queryParams: { query: 'Angular', page: 2, sort: 'date' }
});

// Получатель
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-search',
  template: `
    <p>Поиск: {{ query }}</p>
    <p>Страница: {{ page }}</p>
  `
})
export class SearchComponent implements OnInit {
  query: string = '';
  page: number = 1;

  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    this.route.queryParams.subscribe(params => {
      this.query = params['query'] || '';
      this.page = +params['page'] || 1;
    });
  }
}

Fragment (якорь)

// Переход с фрагментом
this.router.navigate(['/docs'], { fragment: 'installation' });

// Получение фрагмента
this.route.fragment.subscribe(frag => {
  console.log('Фрагмент:', frag);
  // Прокрутка к элементу
  document.getElementById(frag)?.scroll                

Блоги

Рекомендаций по книгам