En mi escenario simplificado, hay un parent que contiene toda la lógica comercial.
El parent crea un componente child que solo es responsable de mostrar una lista de botones.
Quiero manejar los eventos de clic para dichos botones en el parent , pero, al usar el patrón EventEmitter sugerido, me veo obligado a usar un switch case inútil en el parent , para detectar qué botón se presiona.
Sería mucho más fácil pasar directamente las devoluciones de llamada como entrada del child , pero creo que no es una buena práctica. Además, estas devoluciones de llamada, por lo que puedo ver, se ejecutan en el contexto del niño, que no es el resultado deseado.
¿Me estoy perdiendo de algo? ¿Hay una mejor manera de satisfacer mis necesidades? ¿O estoy abordando el problema completamente de manera incorrecta?
El padre:
import { Component } from "@angular/core"; @Component({ selector: "parent", template: ` <child [buttons]="buttons" (click)="onButtonClick($event)" ></child> <span>{{ description }}</span>` }) export class ParentComponent { description = ""; buttons = ["foo", "bar", "baz"]; onButtonClick(button: string) { switch (button) { case "foo": this.description = "Calling foo()"; this.foo(); break; case "bar": this.description = "Calling bar()"; this.bar(); break; case "baz": this.description = "Calling baz()"; this.baz(); break; } } foo() {} bar() {} baz() {} }El niño:
import { Component, EventEmitter, Input, Output } from "@angular/core"; @Component({ selector: "child", template: ` <span *ngFor="let button of buttons"> <button (click)="onClick(button)">{{ button }}</button> </span>` }) export class ChildComponent { @Input() buttons: string[]; @Output() click = new EventEmitter<string>(); onClick(button: string) { this.click.emit(button); } }Y una caja de arena de trabajo.
Podría pensar en proporcionar las devoluciones de llamada dentro de una matriz de objetos en lugar de la matriz de cadenas.
Sandbox editado: https://codesandbox.io/s/cocky-brahmagupta-ueg4nv
El padre
import { Component } from "@angular/core"; @Component({ selector: "parent", template: ` <child [buttons]="buttons" ></child> <span>{{ description }}</span>` }) export class ParentComponent { description = ""; buttons = [ { name: "foo", callback: () => { this.description = "Calling foo()" } }, // bar // baz ]; }El niño
@Component({ selector: "child", template: ` <span *ngFor="let button of buttons"> <button (click)="button.callback()">{{ button.name }}</button> </span>` }) export class ChildComponent { @Input() buttons: MyButton[]; }La interfaz
interface MyButton { name: string, callback: () => void; }Puedes emitir lo que sea
//padre
@Component({ selector: "parent", template: ` <child [buttons]="buttons" (click)="$event()" ></child> <span>{{ description }}</span>` }) export class ParentComponent { description = ""; buttons = [ { name: "foo", callback: this.foo}, { name: "bar", callback: this.bar}, { name: "baz", callback: this.baz}, ]; foo(){} bar(){} baz(){} }//niño
@Component({ selector: "child", template: ` <span *ngFor="let button of buttons"> <button (click)="onClick(button)">{{ button.name }}</button> </span>` }) export class ChildComponent { @Input() buttons: any[]; @Output() click = new EventEmitter<any>(); onClick(button: any) { this.click.emit(button.callback); } }Update Sound "bizarro" pasa una función y ejecuta usando function(), pero necesitamos pensar que una función es solo un objeto.
Imagina que defines dos funciones
function1(){console.log("I'm function 1")} function2(){console.log("I'm function 1")}En un evento click llamamos a una función
click() { const mainFunction=this.function1 mainFunction() //execute the function1 }o según una variable
click() { const mainFunction=this.condicion?this.function1:this.function2 mainFunction() //execute the function1 or the function2 //if condition is true or false }Las variables, objetos, matrices, funciones... se almacenan físicamente en una posición de memoria. el "nombre" de la variable, objeto, función... son sólo un "puntero" a esta memoria.
Si queremos, podríamos en la respuesta escribir
<child [buttons]="buttons" (click)="executeFunction($event)"></child> executeFunction(mainFunction:any) { mainFunction() }Si queremos, podemos escribir la función para dar más claridad si toda nuestra función no tiene argumentos y no devuelve nada, en su lugar, use este feo "cualquier" uso
executeFunction(mainFunction:()=>void) { mainFunction() }Y
@Output() click = new EventEmitter<()=>void>();