Cosa sono le Template Reference Variable e i decoratori @ViewChild @ViewChildren @ContentChild @ContentChildren in Angular
Tags: angular, typescript, javascript, frontend
Published: 2021-02-02 16:31:02

[Stefano Marchisio - sviluppatore freelance: angular | asp.net core mvc c#](https://www.stefanomarchisio.it/)

####Quest'articolo mostra l'uso delle “Template Reference Variable” e come fare delle query DOM attraverso: @ViewChild @ViewChildren @ContentChild @ContentChildren per recuperare referenze

##Template Reference Variable

Una “Template Reference Variable” è una referenza ad un elemento all’interno in un template HTML, e con elemento si intende sia un semplice elemento HTML che un altro componente o direttiva presente nel template HTML. Nel primo caso avremo una referenza ad un elemento del DOM (ed il tipo associato è ElementRef) nel secondo caso una referenza ad un componente o direttiva. Le “Template Reference Variable” vengono anche usate per definire template con cui creare EmbeddedView o per identificare ViewContainer all’interno dei quali creare EmbeddedView. Una “Template Reference Variable” viene dichiarata mettendo il carattere “#” davanti al nome (come fosse un attributo addizionale).

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/pvnf86n066f3oaq4z3oz.png)

Nell'esempio sovrastante viene utilizzato un tag HTML, ma lo stesso discorso vale anche per un componente. Nel momento in cui dichiariamo una “TemplateReferenceVariable”, che per brevità in seguito chiameremo TRV, abbiamo accesso a tutte le proprietà e metodi definiti in quell’oggetto. Una “TRV” può essere utilizzata sia all’interno del templete HTML stesso ( per esempio in un espressione di binding "{  {  }  }" ) sia nel codice TypeScript di un componente. All’interno di un template HTML può anche essere passata come parametro ad un evento.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/viw0jlg2zyzper6zekp8.png)

Sopra si possono vedere 2 esempi: una TRV definita in un elemento HTML e una TRV definita in un component. Se viene dichiarata senza essere inizializzata conterrà una referenza all’elemento o componente. Esiste anche una seconda modalità per dichiararla (vedi sotto).

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/e2fe6aqv15orci21wuyr.png)

In questo caso viene assegnato un valore alle TRV in fase di dichiarazione.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/sqeohr343tcajenlzxl5.png)

Per cui non conterrà più la referenza dell’elemento in cui è stata dichiarata, ma bensì conterrà l’oggetto che gli è stato assegnato (in questo caso la direttiva del FormModule). Nel caso di #f="ngForm", visto che la variabile viene passata ad un evento, nel codice TypeScript al metodo onSubmit(f) verrà passata la direttiva ngForm. Questo mi servirà per recuperare i valori dei campi del form.

@ViewChild(), @ViewChildren(), @ContentChild(), @ContentChildren()

All’interno del codice TypeScript di un componente una “TRV” dichiarata nel template HTML non è visibile ovvero se referenzio il suo nome nel codice otterrò un errore di compilazione. **Ma Angular fornisce un meccanismo chiamato DOM query. Questa funzionalità permette di fare delle query all’interno del template HTML, per ottenere referenze a “Component”, “Directive” e “TRV” (definiti nel templete HTML).** Per far ciò devo usare i decoratori @ViewChild(), @ViewChildren(), @ContentChild(), @ContentChildren() nella dichiarazione di una variabile. 

I primi 2 decoratori: @ViewChild(), @ViewChildren() ispezionano gli elementi che sono nel template HTML direttamente.

I secondi 2 decoratori: @ContentChild(), @ContentChildren() ispezionano gli elementi proiettati ovvero gli elementi presenti all’interno di &lt; ng-content>&lt; /ng-content> 

In entrambi i casi “Child” ritorna un solo elemento, mentre “Children” ritorna più elementi (nel caso la query trovi più elementi che soddisfano il criterio di ricerca).

*Questi decoratori devono essere anteposti alla dichiarazione di una variabile*, un po’ come avviene per i decoratori di @Input(), @Output(). *Sarà poi Angular che in modo automatico effettuera la DOM query e metterà il risultato nella variabile.* L’unica cosa da tener presente è che il risultato potrebbe esserci solo dopo l’evento “ngAfterViewInit”. Prima di tale evento la variabile sarà undefined, se stiamo usando componenti dinamici. Con Angular 8 le cose cambiano leggermente, maggiori informazioni [quì](https://angular.io/guide/static-query-migration). Il tipo di dato contenuto in questa variabile dipenderà invece da cosa stiamo leggendo (ElementRef, TemplateRef, ViewContainerRef, ComponentCustom, DirectiveCustom, etc…)

Fin qui abbiamo visto come recuperare un elemento facendo una DOM query con uno dei decoratori menzionati sopra: @ViewChild(), @ViewChildren(), @ContentChild(), @ContentChildren(). 

Ma esiste anche un’altra modalità! Ora, visto che tutti i componenti sono contenuti dentro un elemento custom del DOM e visto che tutte le direttive sono applicate ad elementi del DOM, componenti e direttive possono ottenere un istanza dell' ElementRef che li contiene tramite dependency injection.
 
*Infatti dichiarando nel costruttore di un componente una variabile ElementRef, verrà passata tramite dependency injection la referenza dell’elemento che contiene il componente. Analogamente, dichiarando nel costruttore di una direttiva una variabile ElementRef, verrà passata tramite dependency injection la referenza dell’elemento a cui è applicata la direttiva.*

ElementRef: fornisce una referenza ad un elemento del DOM. Può essere iniettato nel costruttore di un componet / directive oppure letto tramite: @ViewChild(), @ViewChildren.

TemplateRef: rappresenta il template con cui è possibile creare un EmbeddedView. Può essere iniettato nel costruttore (nel caso si tratti di una direttiva custum) oppure letto tramite: @ViewChild(), @ViewChildren().

ViewContainerRef: rappresenta un contenitore o placeholder dove una o più viste possono essere attaccate. Può essere iniettato nel costruttore oppure letto tramite: @ViewChild(), @ViewChildren().

##Sotto un primo esempio

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/l0ookrqo9wu5nvi9kk5n.png)

In quest’esempio è stata attribuita una “TRV” ad un tag span. Nel codice TypeScript invece, tramite il decoratore @ViewChild leggiamo il valore di questa referenza e la mettiamo nella variabile “tref”. Tale valore sarà poi disponibile nell’evento ngAfterViewInit. 

La sintassi base per dichiarare un decoratore è la seguente. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jtod0c7yxk0311q426vu.png)

Come si può vedere è stato specificato “tref” come “template reference”. Il secondo parametro invece non è sempre obbligatorio, infatti Angular tenta di inferirlo da ciò che stiamo leggendo.

Per cui il decoratore sopra avremmo potuto scriverlo nella forma abbreviata (essendo un semplice elemento HTML viene inferito come ElementRef).

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fz21f0sxa81emmhuyydh.png)

Anche nel caso si debba leggere una “TRV” associata ad un &lt; ng-template> è possibile usare la forma abbreviata (essendo un ng-template viene inferito come TemplateRef). Ci sono dei casi però in cui Angular non riesce ad inferire il tipo, per cui è necessario usare la forma completa. Un tipico esempio è ViewContainerRef.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/8ceo9tzsciux22v4mfcn.png)

In quest’esempio leggiamo un template #tpl1 che viene usato per creare un EmbeddedView da inserire nel ViewContainer identifcato dalla #container1. Come si può vedere abbiamo usato la forma abbreviata per leggere il template, mentre abbiamo usato la forma completa per leggere il viewcontainer. Maggiori informazioni sulla manipolazione del DOM è possibile trovarle nei prossimi articoli.

##Sotto un secondo esempio

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/5km2jsb535psa74banyc.png)

In quest’esempio invece di definire e leggere una “TRV”, leggiamo la referenza di un componente definito nel template HTML. Nel decoratore non verrà passata una stringa con un nome, ma bensì verrà passato il componente. Stesso discorso nel caso volessimo leggere una direttiva custom o una direttiva build-in.

1) [Introduzione ad Angular / Sommario](https://dev.to/mastefano64/introduzione-ad-angular-5ba7)

2) [Angular Component Communication (Data Binding) – parte 1](https://dev.to/mastefano64/angular-component-communication-data-binding-parte-1-321h)

3) [Angular Component Communication (decoratori @Input, @Output) – parte 2](https://dev.to/mastefano64/angular-component-communication-decoratori-input-output-parte-2-368f)

4) [Cosa sono le Template Reference Variable e i decoratori @ViewChild @ViewChildren @ContentChild @ContentChildren in Angular](https://dev.to/mastefano64/cosa-sono-le-template-reference-variable-e-i-decoratori-viewchild-viewchildren-contentchild-contentchildren-in-angular-2a7d)

5) [Cosa sono le “projection” in Angular (ng-content ContentChild ContentChildren)](https://dev.to/mastefano64/cosa-sono-le-projection-in-angular-ng-content-contentchild-contentchildren-aml)

6) [Come manipolare il DOM da un applicazione Angular](https://dev.to/mastefano64/come-manipolare-il-dom-da-un-applicazione-angular-2oj5)

Se volete contattarmi il mio profilo Linkedin è il seguente:
[Stefano Marchisio - sviluppatore freelance: angular | asp.net core mvc c#](https://www.linkedin.com/in/stefano-marchisio-sviluppatore-web-angular-javascript-aspnet-fullstack/)