Il framework Angular è studiato per essere modulato formato da tanti componenti che condividono informazioni e dati tra di loro, nel caso di dati dinamici sono previsti alcuni decorator studiati per semplificare la vita dei programmatori. Prima di tutto bisogna pensare di essere in strutture del tipo annidato: un componente contiene uno o più component. Se il padre volesse inviare un dato dinamico non può usare la tecnica del “Single-slot content projection” o simili in quanto funzionano solo con contenuti statici.
La direttiva di input permette di inviare informazioni dal padre al figlio, per esempio avendo due componenti e volendo passare un valore numerico da un padre ad un figlio:
@Component({ selector: 'app-padre', template: `<app-figlio [valoreF]="valoreP"></app-figlio> <p (click)="addNelPadre()">Aggiungi uno</p>`, styles: [ ] }) export class PadreComponent { valoreP : number =0; ngOnInit(): void { this.valoreP=42; } addNelPadre(){ this.valoreP++;} } //////////////////////////////////////////////////// Component({ selector: 'app-figlio', template: `<p>Il valore è {{valoreF}}</p>`, styles: [ ] }) export class FiglioComponent { @Input() valoreF : number | undefined; }
nell’esempio è stato inserito anche un metodo nel padre per poter modificare il valore (nel padre) e constatare che il valore viene propagato dinamicamente anche nel figlio.
La tecnica per inviare dati ed eventi da un componente ad un genitore prevede l’uso della direttiva @Output e l’uso degli EventEmitter nel caso ci sia la necessità di eseguire un evento nel componente superiore scatenato da un evento del figlio padre, per esempio un bottone nel figlio per eseguire un metodo nel componente padre con la possibilità di far transitare anche un valore (stringa):
@Component({ selector: 'app-padre', template: `<app-figlio [valoreF]="valoreP" (figlioEmitter)="eventoNelFiglio($event)"></app-figlio> <p (click)="addNelPadre()">Aggiungi uno</p>`, styles: [ ] }) export class PadreComponent { valoreP : number =0; ngOnInit(): void { this.valoreP=42; } addNelPadre(){ this.valoreP++;} eventoNelFiglio(value : string){this.valoreP+=Number(value);} } //////////////////////////////////////////////////// @Component({ selector: 'app-figlio', template: `<p>Il valore è {{valoreF}}</p> <label>Add <input #inputF></label> <button (click)="addValue(inputF.value)"> Add to parent's value</button>`, styles: [ ] }) export class FiglioComponent { @Input() valoreF : number | undefined; @Output() figlioEmitter = new EventEmitter<string>(); addValue(value: string){ this.figlioEmitter.emit(value); } }
Questa tecnica prevede anche l’uso di @Input e @Output assieme, nell’esempio appena introdotto il figlio ha due proprietà diverse (una per input e una per output), è possibile inoltre evitare di dover aggiungere le annotation nel codice ma è possibile dichiarare l’elenco delle proprietà coinvolte nella dichiarazione dei meta-dati del componente aggiungendo anche un alias in modo che proprietà del padre e del figlio abbiano nomi diverse:
@Component({ selector: 'app-figlio', template: `<p>Il valore è {{valore}}</p> <label>Add <input #inputF></label> <button (click)="addValue(inputF.value)"> Add to parent's value</button>`, styles: [ ], inputs: ['valore: valoreF'], // propertyName:aliasInParent outputs: ['evento: figlioEmitter'] }) export class FiglioComponent { valore : number | undefined; figlioEmitter = new EventEmitter<string>(); addValue(value: string){ this.evento.emit(value); } }
La documentazione ufficiale è sempre il punto di riferimento di questa tecnica che è da usare ogni volta che è necessario inviare o scambiare dati dinamici tra componenti in un progetto Angular.