Il n'y a pas d'équivalent à $scope.emit()
ou $scope.broadcast()
de AngularJS. EventEmitter à l'intérieur d'un composant se rapproche, mais comme vous l'avez mentionné, il n'émettra qu'un événement au composant parent immédiat.
Dans Angular, il existe d'autres alternatives que je vais essayer d'expliquer ci-dessous.
Les liaisons @Input () permettent au modèle d'application d'être connecté dans un graphe d'objets dirigé (de la racine aux feuilles). Le comportement par défaut de la stratégie de détection des modifications d'un composant consiste à propager toutes les modifications apportées à un modèle d'application pour toutes les liaisons à partir de n'importe quel composant connecté.
À part: Il existe deux types de modèles: Afficher les modèles et Modèles d'application. Un modèle d'application est connecté via des liaisons @Input (). Un modèle de vue est juste une propriété de composant (non décorée avec @Input ()) qui est liée dans le modèle du composant.
Pour répondre à tes questions:
Que faire si j'ai besoin de communiquer entre des composants frères?
Modèle d'application partagé : les frères et sœurs peuvent communiquer via un modèle d'application partagé (tout comme angular 1). Par exemple, lorsqu'un frère modifie un modèle, l'autre frère qui a des liaisons avec le même modèle est automatiquement mis à jour.
Événements de composant : les composants enfants peuvent émettre un événement vers le composant parent à l'aide des liaisons @Output (). Le composant parent peut gérer l'événement et manipuler le modèle d'application ou son propre modèle de vue. Les modifications apportées au modèle d'application sont automatiquement propagées à tous les composants qui se lient directement ou indirectement au même modèle.
Événements de service : les composants peuvent s'abonner aux événements de service. Par exemple, deux composants frères peuvent s'abonner au même événement de service et répondre en modifiant leurs modèles respectifs. Plus d'informations ci-dessous.
Comment puis-je communiquer entre un composant racine et un composant imbriqué à plusieurs niveaux?
- Modèle d'application partagé : le modèle d'application peut être transmis du composant racine aux sous-composants profondément imbriqués via les liaisons @Input (). Les modifications apportées à un modèle à partir de n'importe quel composant se propagent automatiquement à tous les composants qui partagent le même modèle.
- Événements de service : vous pouvez également déplacer EventEmitter vers un service partagé, ce qui permet à n'importe quel composant d'injecter le service et de s'abonner à l'événement. De cette façon, un composant racine peut appeler une méthode de service (généralement une mutation du modèle), qui à son tour émet un événement. Plusieurs couches vers le bas, un composant petit-enfant qui a également injecté le service et s'est abonné au même événement, peut le gérer. Tout gestionnaire d'événements qui modifie un modèle d'application partagé se propage automatiquement à tous les composants qui en dépendent. C'est probablement l'équivalent le plus proche
$scope.broadcast()
de Angular 1. La section suivante décrit cette idée plus en détail.
Exemple d'un service observable qui utilise des événements de service pour propager les modifications
Voici un exemple de service observable qui utilise des événements de service pour propager les modifications. Lorsqu'un TodoItem est ajouté, le service émet un événement notifiant ses abonnés aux composants.
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);
}
}
Voici comment un composant racine souscrirait à l'événement:
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;
}
}
Un composant enfant imbriqué à plusieurs niveaux souscrirait à l'événement de la même manière:
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;
}
}
Voici le composant qui appelle le service pour déclencher l'événement (il peut résider n'importe où dans l'arborescence des composants):
@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));
}
}
Référence: Change Detection in Angular