Es gibt kein Äquivalent zu $scope.emit()
oder $scope.broadcast()
von AngularJS. EventEmitter innerhalb einer Komponente kommt nahe, aber wie Sie bereits erwähnt haben, gibt es nur ein Ereignis an die unmittelbare übergeordnete Komponente aus.
In Angular gibt es andere Alternativen, die ich unten erklären möchte.
Mit @Input () -Bindungen kann das Anwendungsmodell in einem gerichteten Objektdiagramm (Wurzel zu Blättern) verbunden werden. Das Standardverhalten der Änderungsdetektorstrategie einer Komponente besteht darin, alle Änderungen an einem Anwendungsmodell für alle Bindungen einer verbundenen Komponente weiterzugeben.
Nebenbei: Es gibt zwei Arten von Modellen: Ansichtsmodelle und Anwendungsmodelle. Ein Anwendungsmodell ist über @ Input () -Bindungen verbunden. Ein Ansichtsmodell ist nur eine Komponenteneigenschaft (nicht mit @Input () dekoriert), die in der Vorlage der Komponente gebunden ist.
So beantworten Sie Ihre Fragen:
Was ist, wenn ich zwischen Geschwisterkomponenten kommunizieren muss?
Gemeinsames Anwendungsmodell : Geschwister können über ein gemeinsames Anwendungsmodell kommunizieren (genau wie Winkel 1). Wenn beispielsweise ein Geschwister eine Änderung an einem Modell vornimmt, wird das andere Geschwister, das Bindungen an dasselbe Modell aufweist, automatisch aktualisiert.
Komponentenereignisse : Untergeordnete Komponenten können mithilfe von @ Output () - Bindungen ein Ereignis an die übergeordnete Komponente senden. Die übergeordnete Komponente kann das Ereignis verarbeiten und das Anwendungsmodell oder das eigene Ansichtsmodell bearbeiten. Änderungen am Anwendungsmodell werden automatisch an alle Komponenten weitergegeben, die direkt oder indirekt an dasselbe Modell gebunden sind.
Serviceereignisse : Komponenten können Serviceereignisse abonnieren. Beispielsweise können zwei Geschwisterkomponenten dasselbe Serviceereignis abonnieren und darauf reagieren, indem sie ihre jeweiligen Modelle ändern. Mehr dazu weiter unten.
Wie kann ich zwischen einer Root-Komponente und einer Komponente kommunizieren, die mehrere Ebenen tief verschachtelt ist?
- Gemeinsames Anwendungsmodell : Das Anwendungsmodell kann über @Input () -Bindungen von der Root-Komponente an tief verschachtelte Unterkomponenten übergeben werden. Änderungen an einem Modell von einer Komponente werden automatisch an alle Komponenten weitergegeben, die dasselbe Modell verwenden.
- Service Veranstaltungen : Sie können auch die EventEmitter zu einem gemeinsamen Dienst bewegen, die jede Komponente ermöglicht es, den Dienst zu injizieren und zu dem Ereignis abonnieren. Auf diese Weise kann eine Root-Komponente eine Servicemethode aufrufen (die normalerweise das Modell mutiert), die wiederum ein Ereignis ausgibt. Mehrere Ebenen weiter unten kann eine Enkelkomponente, die den Dienst ebenfalls injiziert und dasselbe Ereignis abonniert hat, damit umgehen. Jeder Ereignishandler, der ein freigegebenes Anwendungsmodell ändert, wird automatisch an alle davon abhängigen Komponenten weitergegeben. Dies ist wahrscheinlich das nächste Äquivalent zu
$scope.broadcast()
Angular 1. Im nächsten Abschnitt wird diese Idee ausführlicher beschrieben.
Beispiel eines beobachtbaren Dienstes, der Dienstereignisse verwendet, um Änderungen zu verbreiten
Hier ist ein Beispiel für einen beobachtbaren Dienst, der Dienstereignisse verwendet, um Änderungen weiterzugeben. Wenn ein TodoItem hinzugefügt wird, gibt der Dienst ein Ereignis aus, das seine Komponententeilnehmer benachrichtigt.
export class TodoItem {
constructor(public name: string, public done: boolean) {
}
}
export class TodoService {
public itemAdded$: EventEmitter<TodoItem>;
private todoList: TodoItem[] = [];
constructor() {
this.itemAdded$ = new EventEmitter();
}
public list(): TodoItem[] {
return this.todoList;
}
public add(item: TodoItem): void {
this.todoList.push(item);
this.itemAdded$.emit(item);
}
}
So würde eine Root-Komponente das Ereignis abonnieren:
export class RootComponent {
private addedItem: TodoItem;
constructor(todoService: TodoService) {
todoService.itemAdded$.subscribe(item => this.onItemAdded(item));
}
private onItemAdded(item: TodoItem): void {
// do something with added item
this.addedItem = item;
}
}
Eine untergeordnete Komponente, die mehrere Ebenen tief verschachtelt ist, würde das Ereignis auf dieselbe Weise abonnieren:
export class GrandChildComponent {
private addedItem: TodoItem;
constructor(todoService: TodoService) {
todoService.itemAdded$.subscribe(item => this.onItemAdded(item));
}
private onItemAdded(item: TodoItem): void {
// do something with added item
this.addedItem = item;
}
}
Hier ist die Komponente, die den Dienst aufruft, um das Ereignis auszulösen (sie kann sich an einer beliebigen Stelle im Komponentenbaum befinden):
@Component({
selector: 'todo-list',
template: `
<ul>
<li *ngFor="#item of model"> {{ item.name }}
</li>
</ul>
<br />
Add Item <input type="text" #txt /> <button (click)="add(txt.value); txt.value='';">Add</button>
`
})
export class TriggeringComponent{
private model: TodoItem[];
constructor(private todoService: TodoService) {
this.model = todoService.list();
}
add(value: string) {
this.todoService.add(new TodoItem(value, false));
}
}
Referenz: Änderungserkennung im Winkel