Как передать данные между компонентами?

Передача данных между компонентами в Angular зависит от их взаимного расположения в иерархии. Существует несколько способов передачи данных: через @Input() и @Output() (родитель-дочерний компонент), через сервисы (между любыми компонентами), через маршруты и через глобальное хранилище.

1. Передача данных от родительского компонента к дочернему — @Input

Если один компонент является родителем другого, он может передать данные дочернему компоненту с помощью свойства @Input().

Шаг 1: Дочерний компонент

import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
template: \`<p>Привет, {{ name }}</p>\`
})
export class ChildComponent {
@Input() name!: string;
}

Шаг 2: Родительский компонент

<app-child \[name\]="'Андрей'"></app-child>

Или с переменной:

parentName = 'Мария';
<app-child \[name\]="parentName"></app-child>

Angular автоматически отслеживает изменения входного свойства.

2. Передача данных от дочернего компонента к родительскому — @Output + EventEmitter

Дочерний компонент может передавать события и данные родителю через @Output().

Шаг 1: Дочерний компонент

import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
template: \`<button (click)="notify()">Сообщить родителю</button>\`
})
export class ChildComponent {
@Output() clicked = new EventEmitter<string>();
notify() {
this.clicked.emit('Привет от дочернего компонента');
}
}

Шаг 2: Родительский компонент

<app-child (clicked)="handleMessage($event)"></app-child>
handleMessage(message: string) {
console.log('Получено сообщение:', message);
}

3. Двусторонняя привязка между родителем и дочерним компонентом

Можно реализовать кастомную двухстороннюю привязку, объединив @Input() и @Output():

Шаг 1: Дочерний компонент

@Input() value!: string;
@Output() valueChange = new EventEmitter<string>();
onInput(event: Event) {
const input = event.target as HTMLInputElement;
this.valueChange.emit(input.value);
}
<input \[value\]="value" (input)="onInput($event)">

Шаг 2: Родительский компонент

<app-child \[(value)\]="username"></app-child>

Angular интерпретирует [(value)]="username" как:

\[ value \]="username"
( valueChange )="username = $event"

4. Передача данных между компонентами, не связанными иерархией — через сервис

Сервисы в Angular — это singleton-объекты, которые можно инжектировать в любые компоненты. Они отлично подходят для совместного хранения и передачи состояния.

Шаг 1: Сервис

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class DataService {
private messageSource = new BehaviorSubject<string>('Привет');
currentMessage$ = this.messageSource.asObservable();
changeMessage(message: string) {
this.messageSource.next(message);
}
}

Шаг 2: Отправитель

constructor(private dataService: DataService) {}
updateMessage() {
this.dataService.changeMessage('Новое сообщение');
}

Шаг 3: Получатель

message = '';
constructor(private dataService: DataService) {}
ngOnInit() {
this.dataService.currentMessage$.subscribe(msg => this.message = msg);
}

Использование BehaviorSubject позволяет как получать последние значения, так и подписываться на новые.

5. Передача данных через маршруты (ActivatedRoute и Router)

5.1. Параметры маршрута

{ path: 'user/:id', component: UserComponent }
<a \[routerLink\]="\['/user', 5\]">Профиль</a>

В компоненте:

constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.route.params.subscribe(params => {
console.log('ID:', params\['id'\]);
});
}

5.2. Query параметры

<a \[routerLink\]="\['/search'\]" \[queryParams\]="{ term: 'angular', page: 2 }">Поиск</a>

В компоненте:

this.route.queryParams.subscribe(params => {
console.log(params\['term'\]); // angular
});

6. Передача данных через @ViewChild (из родителя в дочерний компонент по ссылке)

Если дочерний компонент встроен в шаблон родителя, можно получить доступ к его методам и свойствам через @ViewChild.

Шаг 1: Дочерний компонент

@Component({
selector: 'app-child',
template: \`<p>Я дочерний компонент</p>\`
})
export class ChildComponent {
sayHello() {
console.log('Привет из дочернего компонента');
}
}

Шаг 2: Родительский компонент

@ViewChild(ChildComponent) childComponent!: ChildComponent;
ngAfterViewInit() {
this.childComponent.sayHello();
}

Работает только при прямом встраивании компонента, не с динамической загрузкой.

7. Передача данных с помощью @ContentChild и ng-content

Если дочерний компонент использует ng-content для вставки контента, можно получить доступ к переданному компоненту или шаблону через @ContentChild.

@ContentChild(TemplateRef) tpl!: TemplateRef<any>;

Используется в Angular Material, Ng-Zorro и других UI-библиотеках.

8. Использование глобального хранилища (NgRx, SignalStore)

Для сложных приложений можно использовать глобальные state-менеджеры (Redux-подобные):

  • NgRx — фреймворк с actions, reducers, selectors, effects.

  • SignalStore — реактивное хранилище на Angular Signals (начиная с Angular 17).

  • Akita, NgXs, RxAngular — альтернативы.

Пример передачи данных:

store.dispatch(setUser({ user }));
store.select(selectUser).subscribe(user => this.user = user);

9. Локальное хранилище / sessionStorage / window.postMessage

При необходимости можно передавать данные между приложениями, вкладками браузера или сохранять их вне Angular.

10. Обмен данными между sibling-компонентами (на одном уровне)

Вариант 1: Через родителя

  • Родитель содержит данные;

  • Передаёт их в один дочерний компонент;

  • Дочерний вызывает @Output, родитель обновляет данные;

  • Передаёт их другому компоненту.

Вариант 2: Через сервис

  • Компоненты подписываются на один и тот же сервис;

  • Один обновляет данные → другой получает изменения через Subject/BehaviorSubject.

11. Динамическая передача через ComponentFactoryResolver (для динамических компонентов)

Можно передавать данные в компоненты, созданные вручную через ViewContainerRef.createComponent.

const compRef = this.vcRef.createComponent(MyComponent);
compRef.instance.title = 'Динамический компонент';

Подходит для построения модальных окон, вкладок, CMS-систем.