Как передать данные между компонентами?
Передача данных между компонентами в 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-систем.