Não há equivalente para $scope.emit()
ou $scope.broadcast()
do AngularJS. O EventEmitter dentro de um componente se aproxima, mas, como você mencionou, ele emitirá apenas um evento para o componente pai imediato.
No Angular, existem outras alternativas que tentarei explicar abaixo.
As ligações @Input () permitem que o modelo de aplicativo seja conectado em um gráfico de objeto direcionado (raiz às folhas). O comportamento padrão da estratégia do detector de alterações de um componente é propagar todas as alterações em um modelo de aplicativo para todas as ligações de qualquer componente conectado.
Lado: Existem dois tipos de modelos: View Models e Application Models. Um modelo de aplicativo é conectado através de ligações @Input (). Um modelo de exibição é apenas uma propriedade de componente (não decorada com @Input ()) que é vinculada ao modelo do componente.
Para responder suas perguntas:
E se eu precisar me comunicar entre os componentes irmãos?
Modelo de aplicativo compartilhado : os irmãos podem se comunicar por meio de um modelo de aplicativo compartilhado (assim como o angular 1). Por exemplo, quando um irmão faz uma alteração em um modelo, o outro irmão que tem ligações ao mesmo modelo é atualizado automaticamente.
Eventos do componente : os componentes filhos podem emitir um evento para o componente pai usando as ligações @Output (). O componente pai pode manipular o evento e manipular o modelo de aplicativo ou seu próprio modelo de visualização. As alterações no modelo de aplicativo são propagadas automaticamente para todos os componentes que se ligam direta ou indiretamente ao mesmo modelo.
Eventos de serviço : os componentes podem se inscrever em eventos de serviço. Por exemplo, dois componentes irmãos podem se inscrever no mesmo evento de serviço e responder modificando seus respectivos modelos. Mais sobre isso abaixo.
Como posso me comunicar entre um componente raiz e um componente aninhado em vários níveis?
- Modelo de Aplicativo Compartilhado : O modelo de aplicativo pode ser passado do componente Raiz para subcomponentes profundamente aninhados através de ligações @Input (). As alterações em um modelo de qualquer componente serão propagadas automaticamente para todos os componentes que compartilham o mesmo modelo.
- Eventos de serviço : Você também pode mover o EventEmitter para um serviço compartilhado, o que permite que qualquer componente injete o serviço e se inscreva no evento. Dessa forma, um componente Raiz pode chamar um método de serviço (normalmente modificando o modelo), que por sua vez emite um evento. Várias camadas abaixo, um componente neto que também injetou o serviço e se inscreveu no mesmo evento, pode lidar com isso. Qualquer manipulador de eventos que altere um Modelo de Aplicativo compartilhado será propagado automaticamente para todos os componentes que dependem dele. Este é provavelmente o equivalente mais próximo
$scope.broadcast()
do Angular 1. A próxima seção descreve essa idéia com mais detalhes.
Exemplo de um serviço observável que usa eventos de serviço para propagar alterações
Aqui está um exemplo de um serviço observável que usa eventos de serviço para propagar alterações. Quando um TodoItem é adicionado, o serviço emite um evento notificando seus assinantes de componentes.
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);
}
}
Aqui está como um componente raiz se inscreveria no evento:
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;
}
}
Um componente filho aninhado em vários níveis se inscreveria no evento da mesma maneira:
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;
}
}
Aqui está o componente que chama o serviço para acionar o evento (ele pode residir em qualquer lugar da árvore de componentes):
@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));
}
}
Referência: detecção de alterações em angular