No hay un equivalente a $scope.emit()
, o $scope.broadcast()
desde AngularJS. EventEmitter dentro de un componente se acerca, pero como mencionó, solo emitirá un evento al componente primario inmediato.
En Angular, hay otras alternativas que intentaré explicar a continuación.
Los enlaces @Input () permiten que el modelo de aplicación se conecte en un gráfico de objeto dirigido (raíz a hojas). El comportamiento predeterminado de la estrategia del detector de cambios de un componente es propagar todos los cambios a un modelo de aplicación para todos los enlaces desde cualquier componente conectado.
Aparte: hay dos tipos de modelos: Ver modelos y Modelos de aplicación. Un modelo de aplicación está conectado a través de enlaces @Input (). Un modelo de vista es solo una propiedad de componente (no decorada con @Input ()) que está vinculada en la plantilla del componente.
Para responder tu pregunta:
¿Qué sucede si necesito comunicarme entre componentes hermanos?
Modelo de aplicación compartida : los hermanos pueden comunicarse a través de un modelo de aplicación compartida (al igual que angular 1). Por ejemplo, cuando un hermano hace un cambio en un modelo, el otro hermano que tiene enlaces al mismo modelo se actualiza automáticamente.
Eventos de componentes : los componentes secundarios pueden emitir un evento al componente principal mediante enlaces @Output (). El componente principal puede manejar el evento y manipular el modelo de aplicación o su propio modelo de vista. Los cambios en el modelo de aplicación se propagan automáticamente a todos los componentes que se unen directa o indirectamente al mismo modelo.
Eventos de servicio : los componentes pueden suscribirse a eventos de servicio. Por ejemplo, dos componentes hermanos pueden suscribirse al mismo evento de servicio y responder modificando sus respectivos modelos. Más sobre esto a continuación.
¿Cómo puedo comunicarme entre un componente raíz y un componente anidado a varios niveles de profundidad?
- Modelo de aplicación compartida : el modelo de aplicación se puede pasar del componente raíz a subcomponentes profundamente anidados mediante enlaces @Input (). Los cambios en un modelo desde cualquier componente se propagarán automáticamente a todos los componentes que compartan el mismo modelo.
- Eventos de servicio : también puede mover EventEmitter a un servicio compartido, que permite que cualquier componente inyecte el servicio y se suscriba al evento. De esa manera, un componente raíz puede llamar a un método de servicio (generalmente mutando el modelo), que a su vez emite un evento. Varias capas hacia abajo, un componente de nieto que también ha inyectado el servicio y suscrito al mismo evento, puede manejarlo. Cualquier controlador de eventos que cambie un modelo de aplicación compartido se propagará automáticamente a todos los componentes que dependen de él. Este es probablemente el equivalente más cercano a
$scope.broadcast()
Angular 1. La siguiente sección describe esta idea con más detalle.
Ejemplo de un servicio observable que usa eventos de servicio para propagar cambios
Aquí hay un ejemplo de un servicio observable que usa eventos de servicio para propagar cambios. Cuando se agrega TodoItem, el servicio emite un evento que notifica a sus suscriptores 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);
}
}
Así es como un componente raíz se suscribiría al 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;
}
}
Un componente hijo anidado en varios niveles profundos se suscribiría al evento de la misma manera:
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;
}
}
Aquí está el componente que llama al servicio para activar el evento (puede residir en cualquier parte del árbol 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));
}
}
Referencia: Detección de cambios en angular