Stefano Marchisio - sviluppatore freelance: angular | asp.net core mvc c#
Quest'articolo mostra l'uso dei decoratori di @Input, @Output per passare dati piuttosto che ricevere eventi.
Nella prima parte di quest’articolo abbiamo introdotto il concetto di data binding e come può essere implementato in Angular: Iterpolation, Property binding, Event binding, TwoWay binding. In questa seconda parte continuiamo il discorso sul’ “Angular Component Communication” e parleremo dei decoratori di @Input, @Output.
Angular à un framework a componenti, ed il template HTML di ogni componente può contenere al suo interno altri componenti in modo da formare una struttura ad albero. Detto questo nasce la necessità che i componenti siano in grado comunicare tra loro. In particolar modo che un componente padre possa inviare dati a componenti figlio, così come un componente figlio possa inviare dati al componente padre sotto forma di evento.
Questa funzionalità in Angular è fornita tramite decoratori di @Input(), @Output(). Un decoratore è una funzione preceduta dal carattere “@”, e deve essere posto in fase di dichiarazione prima di una variabile.
Sopra si può vedere un esempio di dichiarazione di un parametro di Input. Nella dichiarazione del parametro di Output assegniamo alla variabile l’oggetto “EventEmitter” (che può essere tipizzato). L’oggetto “EventEmitter” è un Observable e possiede un metodo “emit()”, questo metodo viene invocato quando vogliamo lanciare l’evento. Sotto possiamo vedere un esempio completo di 2 componenti: padre e figlio.
Parent Component
Child Component
Come si può vedere, nel template HTML del “Parent component” è stato dichiarato il “Child Component” , ed il tag ha una proprietà di binding “data” che rappresenta il parametro che vogliamo passare. All’interno del “Child Component” è stata poi dichiarata una variabile preceduta dal decoratore @Input(), questo fa si che Angular metta in questa variabile ciò che era presente nella proprietà di binding “data” del “Parent component”.
Per quanto riguarda i parametri di Output, nel “Child Component” è stata dichiarata una variabile preceduta dal decoratore @Output(). Nel momento in cui vogliamo sollevare l’evento basta richiamare il metodo “emit()” passando come parametro l’argomento che vogliamo ritornare. All’interno del “Parent component” devo infine dichiarare un event-handler che riceva tale evento.
I parametri di Input sono disponibili solo dopo l’evento ngOnInit e vengono aggiornati nel caso di modifiche. Nel nostro esempio troviamo un solo parametro di input, ma in un componente possono essere presenti n. parametri di Input. Come detto all’inizio Angular è un framework a componenti ed ogni componente ha un proprio “lifecycle” scandito da eventi che è possibile intercettare. Tra questi ngOnChanges(changes: SimpleChanges) notifica quando un parametro di Input viene modificato. Come si può vedere quest’evento ha un argomento “SimpleChanges” che contiene i parametri di Input modificati ed i relativi valori (correnti e vecchi).
Con la sintassi base per la dichiarazione di un parametro di Input ovvero quella che antepone il decoratore @Input() davanti al nome di una variabile, posso lanciare un operazione su dati solo nell’evento ngOnInit. Ora, visto che l’evento ngOnInit viene eseguito una sola volta all’atto della creazione di un componente, in seguito se un parametro di Input cambia non siamo in grado di rilanciare un operazione sui dati. L’evento ngOnChanges(changes: SimpleChanges) può risultare utile in un contesto simile, perché notifica tutte le volte che un parametro di Input viene modificato, permettendoci di rilanciare eventuali operazioni sui dati.
Nel caso abbiamo la necessità di rilanciare un operazione sui dati tutte le volte che un parametro di Input viene modificato, ma non vogliamo utilizzare l’evento ngOnChanges(changes: SimpleChanges), abbiamo un’altra possibilità. Dichiarare il parametro di Input con getter e setter.
In questo modo quando il parametro di Input viene modificato, viene automaticamente invocato il metodo this.updatePeriodTypes().
Una cosa importante che dobbiamo tenere in considerazione è questa. Abbiamo detto che Angular notifica tramite l’evento ngOnChanges(changes: SimpleChanges) quando un parametro di Input viene modificato. Senza entrare troppo nel dettaglio, questo avviene confrontando i vecchi valori con i nuovi, e nel caso risultano diversi scatta la notifica. Per questo motivo dobbiamo tenere in considerazione se stiamo operando con tipi valore o tipi referenza (un’oggetto). Se stiamo lavorando con un oggetto e modifichiamo il valore di una sua proprietà, Angular non si accorge della modifica perché la referenza non è cambiata, per questo motivo l’evento ngOnChanges(changes: SimpleChanges) non scatterà.
A questo punto potremmo continuare il discorso parlando di “Immutabilità degli oggetti” e di “OnPush Change Detection Strategy” ma non fa parte di quest’articolo.
Subject
Una delle regole fondamentali quando si parla di architetture software è che ci sia un debole accoppiamento tra le parti, ovvero che non ci creino situazioni in cui una parte dipende dall’altra a causa ad una referenza tipizzata. Con i decoratori di @Input / @Output possiamo mettere in comunicazione 2 componenti nel caso ci sia una relazione padre e figlio, senza incorrere in questo tipo di problemi. Nel caso invece tra 2 o più componenti non ci sia una relazione padre e figlio dobbiamo usare altre tecniche per raggiungere lo scopo. In Angular ci viene in aiuto il Subject che è un tipo speciale di Observable (infatti un Subject è al tempo stesso Observer e Observable). Per cui se creiamo un servizio singleton che incapsuli un Subject, permettiamo a n. componenti di registrarsi e rimanere in attesa di notifiche, che possono provenire da altri componenti. In questo modo l’unica dipendenza che ha un componente è quella del servizio. Sotto un esempio.
1) Introduzione ad Angular / Sommario
2) Angular Component Communication (Data Binding) – parte 1
3) Angular Component Communication (decoratori @Input, @Output) – parte 2
5) Cosa sono le “projection” in Angular (ng-content ContentChild ContentChildren)
6) Come manipolare il DOM da un applicazione Angular
Se volete contattarmi il mio profilo Linkedin è il seguente:
Stefano Marchisio - sviluppatore freelance: angular | asp.net core mvc c#
Top comments (0)