Cosa sono le “projection” in Angular (ng-content ContentChild ContentChildren)
Tags: angular, typescript, javascript, frontend
Published: 2021-02-02 17:05:13

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

####Quest'articolo spiega il concetto di projection in Angular, l'uso del tag ng-content e come recuperare il contenuto proiettato attraverso i decoratori: @ContentChild @ContentChildren

Angular è un framework per sviluppare SPA a componenti. Ogni elemento che vediamo nella UI è un componente ed un componente a sua volta può essere inserito all’interno di un altro componente formando una struttura ad albero. Le projection sono un concetto molto importante in Angular, e servono a creare componenti scalabili e flessibili.

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

Come si può vedere abbiamo definito un semplice componente Angular che può essere riutilizzato tutte le volte che vogliamo inserendo il selettore &lt; app-home> &lt; /app-home> in un templete HTML. Come si può notare, pur avendo creato un componente riutilizzabile, non è molto flessibile perché le 2 righe di testo contenute nel template sono fisse così come i tag HTML. Per rendere la cosa più dinamica possiamo trasformarlo nel seguente modo.

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

Come si può vedere il testo è diventato dinamico, infatti viene passato tramite proprietà di input nel selettore &lt; app-home> 
&lt; /app-home>. Il problema è che title e content hanno i rispettivi tag HTML,definiti all’interno del template dell’ HomeComponent, che rimangono fissi. Come possiamo fare se vogliamo che il title in alcuni casi sia visualizzato con H1 ed in altri con H2? Senza inserire delle istruzioni condizionali all’interno del template dell’ HomeComponent. La risposta è utilizzare le Angular “projection”.

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

Come si può vedere, oltre a passare dei dati ad un componente attraverso i parametri di input ( quelli definiti col decoratore @Input() ) è anche possibile passarli inserendoli tra il tag di aperture e chiusura di un componente. All’interno del componente troveremo poi un nuovo tag &lt; ng-content> &lt; /ng-content>. **Questo nuovo tag è un placeholder ovvero definisce la posizione in cui inserire “testo” passato tra il tag di apertura e chiusura di un component.** Ho detto “testo”, ma può anche essere uno spezzone di codice HTML composto da più tag, piuttosto che un altro componente angular. In quest’ esempio il content continua ad essere passato come parametro di input. Come possiamo fare invece per passare sia title che content all’interno del tag di apertura e chiusura?

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

Come si può vedere troviamo ora 2 ng-content, il tag ng-content possiede un attributo addizionale “select” che funziona in modo analogo ad un selettore CSS. Per cui ogni ng-content visualizzerà solo gli elementi che soddisfano il criterio specificato, che nel nostro caso è h1 e span. Essendo simile ad un selettore CSS funziona anche con classi CSS. **Con questi semplici esempi abbiamo spiegato quello che in Angular è chiamato “projection”.**

Nell’articolo riguardante le “Template Reference Variable” abbiamo introdotto i decoratori: @ViewChild(), @ViewChildren(), @ContentChild(), @ContentChildren(). In quell’articolo è stato spiegato che: i primi 2 ispezionano gli elementi che sono nel template HTML direttamente mentre i secondi 2 ispezionano gli elementi proiettati ovvero gli elementi presenti all’interno di &lt; ng-content> &lt; /ng-content>.

Anche se abbiamo già avuto modo di intuire alcune cose, approfondiremo ora come utilizzare i decoratori @ContentChild(), @ContentChildren() per ritrovare referenze di componenti proiettati. Sotto possiamo vedere 3 componenti: PageComponent, TabsComponent, TabComponent.

##PageComponent

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

##TabsComponent

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

##TabComponent

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

Come si può vedere all’interno del componente PageConponent è stato inserito un componente TabsComponent, ed all’interno del tag di apertura e chiusura sono stati inseriti 3 componenti TabComponent. Nel momento in cui eseguiamo il codice, l’output è quello dell’immagine sottostante.

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

La posizione dell’output dei 3 componenti TabComponent (contenuti all’interno del tag di apertura e chiusura del componente TabsComponent) è determinata dai tag &lt; ng-content> &lt; /ng-content>. Nel nostro caso ne abbiamo 3 ed ognuno ha un attributo “select “ impostato sul valore di una classe CSS. In questo modo stabilisco nella posizione che voglio nel template HTML del componente TabsComponent, inoltre tra un &lt; ng-content> &lt; /ng-content> e l’altro può esserci altro testo (come nel nostro caso). Nel codice TypeScript dei primi 2 componenti possiamo notare altre cose interessati.

Nel componente PageComponent troviamo i seguenti decoratori

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

In questo modo children1 e children2 contengono le referenze del componente TabsComponent e dei 3 componenti TabComponent. All’interno del componente PageComponent, non essendo ancora stati proiettati uso il decoratore @ViewChild.

All’interno del componente TabsComponent, tanto per intenderci quello nel cui template HTML trovo i 3 &lt; ng-content> &lt; /ng-content>, i componenti TabComponent sono già stati proiettati. Per cui se voglio recuperare le loro referenze devo usare il decoratore.

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

Una cosa che vale per tutti i decoratori ( @ViewChild(), @ViewChildren(), @ContentChild(), @ContentChildren() ), il valore recuperato è disponibile dopo l’evento ngAfterViewInit. Prima di tale evento le variabili potrebbero avere valore undefined se stiamo usando componenti dinamici. Con Angular 8 le cose cambiano leggermente, maggiori informazioni [quì](https://angular.io/guide/static-query-migration).

Con quest’articolo si completa il discorso sull’ “Angular Component Communication” ovvero sulla necessità che i componenti possano comunicare tra loro.

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/)