Как обмениваться данными/изменениями между компонентами
Допустим, у вас есть интерфейс с панелью инструментов, боковой панелью и сеткой. На панели инструментов есть раскрывающийся список, в котором при изменении пользователя изменяется содержимое боковой панели и сетки. Вернувшись в Angular 1, я бы использовал Сервис, чтобы получить все свои динамические данные. Когда что-то меняется в службе, все компоненты, которые используют эту службу, также будут обновляться.
В Angular 2 похоже, что люди используют разные методы. Я хотел получить ваш вклад, который является предпочтительным способом.
- Статическая служба
- OnChanges
- Входы и выходы
У меня остается вопрос: лучше ли создавать новую службу для каждого элемента данных, который используется совместно для компонентов, или же у нас может быть только одна служба, в которой есть объект, в котором хранятся все общие данные?
Original Plunker
- Каждое изменение будет иметь свой собственный сервис
app.component.ts
import {Component} from 'angular2/core';
import {NavService} from '../services/NavService';
@Component({
selector: 'obs-comp',
template: 'obs component, item: {{item}}'
})
export class ObservingComponent {
item: number;
subscription: any;
constructor(private _navService:NavService) {}
ngOnInit() {
this.item = this._navService.navItem();
this.subscription = this._navService.navChange$.subscribe(
item => this.selectedNavItem(item));
}
selectedNavItem(item: number) {
this.item = item;
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
@Component({
selector: 'my-nav',
template:'
<div class="nav-item" (click)="selectedNavItem(1)">nav 1 (click me)</div>
<div class="nav-item" (click)="selectedNavItem(2)">nav 2 (click me)</div>
',
})
export class Navigation {
item = 1;
constructor(private _navService:NavService) {}
selectedNavItem(item: number) {
console.log('selected nav item ' + item);
this._navService.changeNav(item);
}
}
@Component({
selector: 'my-app',
template: '{{title}}
<p>
<my-nav></my-nav>
<button (click)="showObsComp = !showObsComp">toggle ObservingComponent</button>
<div *ngIf='showObsComp'>
<obs-comp></obs-comp>
</div>
',
directives: [Navigation, ObservingComponent]
})
export class AppComponent {
title = "Angular 2 - event delegation";
showObsComp = true;
constructor() { console.clear(); }
}
NavService.ts:
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/share';
export class NavService {
private _navItem = 0;
navChange$: Observable<number>;
private _observer: Observer;
constructor() {
this.navChange$ = new Observable(observer =>
this._observer = observer).share();
// share() allows multiple subscribers
}
changeNav(number) {
this._navItem = number;
this._observer.next(number);
}
navItem() {
return this._navItem;
}
}
index.html
<!DOCTYPE html>
<html>
<head>
<title>User Input</title>
<link rel="stylesheet" href="styles.css">
<script src="https://code.angularjs.org/2.0.0-beta.11/angular2-polyfills.js"></script>
<script src="https://code.angularjs.org/tools/system.js"></script>
<script src="https://code.angularjs.org/tools/typescript.js"></script>
<script src="https://code.angularjs.org/2.0.0-beta.11/Rx.js"></script>
<script src="https://code.angularjs.org/2.0.0-beta.11/angular2.dev.js"></script>
<script>
System.config({
transpiler: 'typescript',
typescriptOptions: { emitDecoratorMetadata: true },
packages: {
app: {defaultExtension: 'ts'},
services: {defaultExtension: 'ts'},
}
});
System.import('app/boot')
.then(null, console.error.bind(console));
</script>
</head>
<body>
<my-app>Loading...</my-app>
</body>
</html>
приложение /boot.ts
import {bootstrap} from 'angular2/platform/browser';
import {AppComponent} from './app.component';
import {NavService} from '../services/NavService';
bootstrap(AppComponent, [NavService]);
Revised Plunker for example
- только один сервис, который хранит все данные в объекте. Тип будет передан каждому слушателю, чтобы проверить, нужно ли ему что-либо делать на основе этого типа.
Ответы
Ответ 1
Вы можете использовать общий сервис для этого. Он может содержать как данные, так и наблюдаемые, на которые можно подписаться, чтобы получать уведомления при обновлении данных.
Услуги
export class ListService {
list1Event: EventEmitter<any> = new EventEmitter();
getLists() {
return this.http.get(url).map(res => res.json())
.subscribe(
(data) => {
this.list1Event.emit(data.list1);
}
);
}
}
Компонент
@Component({
selector: 'my-component1',
template: '
<ul>
<li *ngFor="#item of list">{{item.name}}</li>
</ul>
'
})
export class MyComponent1 {
constructor(private service:ListService) {
this.service.list1Event.subscribe(data => {
this.list = data;
});
}
}
самонастройки
bootstrap(AppComponent, [ ListService ]);
Смотрите этот вопрос для более подробной информации:
Ответ 2
В вашем случае использования я использовал бы службы. Службы используются для передачи своих данных другим компонентам. Один компонент мог обновить эти данные для службы, а другой компонент мог бы прочитать ее. Или оба компонента могли просто читать из него, а сам сервер получает данные из "внешнего мира".
Вы используете input
для передачи данных от родителя к дочернему элементу, и вы используете output
для вывода событий из дочернего элемента в родительский.
Вы используете ngOnChanges
, чтобы что-то делать, когда что-то изменяется в самом компоненте, но я предпочитаю использовать для этого функции get()
и set()
.
По крайней мере, это мое занятие:)