Tengo un componente "inteligente" llamado ItemsComponent y dos componentes "tontos" anidados, ItemsListComponent y ItemComponent .
La plantilla html de ItemsComponent contiene ItemsListComponent .
// ItemsComponent <div> // ItemsListComponent <app-items-list [items]="items" (doDelete)="deleteItem($event)" > </app-items-list> <div>y tiene una función llamada deleteItem :
deletItem(item) { // code to handle item deletion... }ItemsListComponent contiene ItemComponent :
// ItemsListComponent <ul *ngFor="let item of items"> // ItemComponent <app-item [item]="item" (doDelete)="deleteItem($event)" > </app-item> </ul>Así que la estructura html es así:
ItemsComponent (app-items) - ItemsListComponent (app-items-list) - ItemComponent (app-item)ItemComponent tiene un botón
<button (click)="deleteItem(item)">y un emisor de eventos para deleteItem :
@Output() doDelete = new EventEmitter(); deleteItem(item) { this.doDelete.emit(item); }Cuando se hace clic en el botón Eliminar en ItemComponent , el evento solo aparece en su padre inmediato, ItemsListComponent , pero no llega a ItemsComponent a menos que agregue una funcionalidad de emisor de eventos idéntica a ItemsListComponent .
Componente de la lista de elementos malolientes :
@Output() doDelete = new EventEmitter(); deleteItem(item) { this.doDelete.emit(item); }Funciona de esta manera, pero ItemsListComponent ahora comparte el olor del código con ItemsComponent , ya que ambos tienen el mismo emisor de eventos y el evento debe pasar de un componente a otro en su camino hacia arriba.
¿Hay una mejor manera de hacer esto?
Como se habrá dado cuenta, los eventos angulares personalizados no burbujean, por lo que si tiene un componente profundamente anidado y desea pasar un evento a un componente superior, cada componente intermedio tiene que delegar el evento hacia arriba.
Otra opción es mover su funcionalidad deleteItem a un servicio que se inyecta en uno de sus componentes de nivel inferior. De esa forma, la función se puede llamar en el punto donde ocurre, en lugar de tener que subir el evento en la jerarquía de vistas.
En realidad, puede hacer que suceda utilizando un CustomEvent en lugar de un EventEmitter . Esto es solo una solución, especialmente porque los patrones de comunicación de Angular están bien descritos en la documentación de Angular y en muchos otros lugares .
Básicamente, debe activar un CustomEvent desde el niño interno y simplemente escucharlo en el componente más externo (el abuelo).
Componente más externo
@Component({ selector: 'outermost', template: `<child></child>` }) export class OutermostComponent { @HostListener('FormSubmitCustomEvent', ['$event']) onCustomEventCaptured(event: any) { console.log('Event Received', event.detail); } }ChildComponent
@Component({ selector: 'child', template: `<inner-child></inner-child>` }) export class ChildComponent { }Componente de niño interno
@Component({ selector: 'inner-child', template: `<button (click)="onSubmit()"></button>` }) export class InnerChildComponent { constructor(private elementRef: ElementRef) {} onSubmit(): void { const event: CustomEvent = new CustomEvent('FormSubmitCustomEvent', { bubbles: true, detail: { data: 'Hello from Inner Child' } }); this.elementRef.nativeElement.dispatchEvent(event); } }Aquí hay un bombardeo de trabajo: https://stackblitz.com/edit/angular-5wv8p5