
GUIDE PER ASPIRANTI PROGRAMMATORI
Il template in Angular
A questo punto dovremmo aver acclarato che un template è un blocco di codice HTML associato ad un componente, che ne rappresenta la parte grafica. Abbiamo già visto che la CLI genera per noi ogni componente in forma di più files associati; il template è contenuto nel file *.component.html, linkato al codice TypeScript tramite la…


Vuoi avviare una nuova carriera o fare un upgrade?
Trova il corso Digital & Tech più adatto a te nel nostro catalogo!
- Le direttive in Angular
- I componenti in Angular
- Il template in Angular
- Le direttive strutturali in Angular
- La content projection in Angular
- I servizi in Angular
- Le Pipes in Angular
- Routing in Angular
- Invio di form in Angular
- Built-in control flow in Angular
- Deferrable views in Angular
- Image optimization in Angular
A questo punto dovremmo aver acclarato che un template è un blocco di codice HTML associato ad un componente, che ne rappresenta la parte grafica.
Abbiamo già visto che la CLI genera per noi ogni componente in forma di più files associati; il template è contenuto nel file *.component.html, linkato al codice TypeScript tramite la proprietà templateUrl:
@Component({ selector: 'app-component', templateUrl: './app.component.html', })
Nei casi più semplici possiamo inserire il template di un componente direttamente nel suo file *.component.ts, rimuovendo la proprietà templateUrl e usando invece template:
@Component({ selector: 'app-component', template: '<h1>Hello World!</h1>', })
La template syntax è una combinazione di codice HTML classico e un set di sintassi specifiche con cui Angular applica diversi concetti del framework; praticamente tutti i tag HTML sono supportati, fanno eccezione quei tag che normalmente rappresentano una pagina HTML intera e non una sua sezione, come <html> <body> e <base>; per ragioni di sicurezza, anche il tag <script> viene ignorato da Angular se presente.
L’ interpolazione in Angular.
L’interpolazione, che abbiamo già visto, è la sintassi più semplice in assoluto: consiste nel rappresentare un’espressione JavaScript tra doppie parentesi graffe; normalmente questa sintassi viene utilizzata per effettuare dei semplici data binding tra proprietà della classe componente e parti del template, ma può essere utilizzata anche per rappresentare valori statici o calcoli.
Vediamo qualche esempio valido:
{{ 'Hello world!' }} {{ 'Hello world!'.replace('!', '?') }} {{ 2 * 1000 }} {{ 2 }} {{ count }} {{ counte.toFixed(2) }}
Poiché tutte le variabili accessibili dal template provengono alla classe componente, la parola chiave this è facoltativa.
Ovviamente l’interpolazione si usa principalmente per mescolare testo statico e porzioni dinamiche che devono essere popolate con i dati del componente:
@Component({ selector: 'app-component', template: '<h1>Name: {{firstName}}; Surname: {{lastName}}</h1>', }) export class AppComponent { firstName = 'Mario'; lastName = 'Rossi'; }
Data binding.
Un altro caso d’uso per l’interpolazione è quello di passare valori dinamici agli attributi dei tag presenti nel template:
@Component({ // ... template: '<input value="{{value}}">' }) export class AppComponent { value = 42; }
È importante notare che in questo modo possiamo interpolare solo testo, perciò non ci consente di passare riferimenti a oggetti o array; per fare questo possiamo utilizzare la sintassi di data binding vera e propria:
<input [value]="value">
In questo caso, nel momento in cui mettiamo l’attributo value tra parentesi quadre, ammettiamo come valore qualunque dato proveniente dalla component class. Questa sintassi è particolarmente utile se combinata con l’utilizzo di input property sui componenti figli.
Prendiamo l’esempio di un componente <app-profile> che rappresenti il profilo di un utente; ecco il suo profile.component.html:
<p>Profile of {{user.name}}</p> <p>Age: {{user.age}}</p> <img [src]="user.imageUrl" alt="profile pic">
Questo componente ha una proprietà user che contiene un oggetto con diverse proprietà, rappresentate nel template; vediamo come un componente padre può usare il componente <app-profile> per rappresentare un oggetto come user.
Innanzitutto guardiamo il codice della classe componente profile.component.ts:
import { Component, Input } from '@angular/core'; export interface User { name: string; age: number; imageUrl: string; } @Component({ selector: 'app-profile', standalone: true, imports: [], templateUrl: './profile.component.html', styleUrl: './profile.component.css' }) export class ProfileComponent { @Input({ required: true }) user!: User; }
Qui abbiamo definito l’interfaccia User, e l’abbiamo usata per tipizzare la proprietà user.
Guardando questa proprietà, notiamo altre due cose:
- la prima è che essa è decorata con @Input() e che è required; questo significa che qualunque componente padre sarà costretto a passare un utente da mostrare al componente profile;
- la seconda è che abbiamo applicato una non-null assertion sulla proprietà usando !, dal momento che sappiamo con certezza che questo componente verrà sempre renderizzato con un data binding del tipo [user]=”…”, e dunque non sarà mai undefined.
Ora vediamo il suo componente padre, app.component.ts:
import { Component } from '@angular/core'; import { ProfileComponent, User } from './profile/profile.component'; @Component({ selector: 'app-root', standalone: true, imports: [ProfileComponent], template: '<app-profile [user]="user" />' }) export class AppComponent { user: User = { name: 'John Doe', age: 30, imageUrl: '/some/image.jpg' }; }
Questo componente importa ProfileComponent e l’interfaccia User, dopodiché fa esattamente quello che ci aspetteremmo: passa il valore di una sua proprietà di tipo User al componente figlio usando un data binding sull’attributo [user].
Per il momento il meccanismo di funzionamento dei data binding dovrebbe essere chiaro; più avanti approfondiremo le input property e il rispettivo decoratore in maniera più esaustiva.
Event binding.
Abbiamo visto che il data binding ci permette di trasmettere dati giù per l’alberatura dei componenti; ma se volessimo far risalire dei dati?
Tendenzialmente il flusso di dati all’interno di un albero di componenti è unidirezionale, dall’alto verso il basso; la comunicazione a ritroso non si fa dunque passando dati, ma scatenando eventi. Vediamo, dunque, un esempio molto semplice di event binding.
Nel nostro app.component.ts vogliamo rappresentare un input e raccogliere in una proprietà del componente il valore aggiornato:
import { Component } from '@angular/core'; @Component({ selector: 'app-root', standalone: true, imports: [], template: '<input #el (input)="onInput(el.value)" /> <p>value: {{value}}</p>' }) export class AppComponent { value: string | undefined = undefined; onInput(value: string) { this.value = value } }
Vediamo bene cosa succede qui:
- il template rappresenta un input, si lega al suo evento input e vi aggancia come event listener il metodo onInput;
- onInput riceve come parametro un valore stringa, che usa per aggiornare la proprietà value;
- sempre nel template, un paragrafo ci rappresenta il valore della proprietà value, e il cerchio si chiude.
Similarmente ai data binding, gli event binding possono essere usati tra componenti usando le output properties e il decoratore @Output(); il meccanismo, tuttavia, è un po’ più complicato, perciò non lo approfondiamo immediatamente: lo faremo più avanti in un capitolo dedicato.
Intanto, riguardando l’esempio appena fatto, possiamo chiederci: ma che cos’è quello strano attributo #el nell’input?
Ebbene, quella è una template variable, cioè una variabile che rappresenta il riferimento all’elemento input e può essere utilizzata in tutto il resto del template; per esempio, qui l’abbiamo usata per passare il valore a onInput.
Template reference.
In Angular è possibile identificare con una template variable (cioè un attributo che inizia con #) tre tipi di riferimento, in base al tipo di tag su cui applichiamo la variabile; i primi due tipi li possiamo facilmente immaginare:
- se la variabile è applicata su un tag HTML nativo, farà riferimento all’elemento stesso;
- se questa viene applicata sul tag di un componente farà riferimento all’istanza della classe componente.
Quanto al terzo tipo, per spiegarlo dobbiamo introdurre un tag speciale di Angular: ng-template.
Questo tag viene utilizzato esclusivamente per rappresentare il suo contenuto, e non viene renderizzato sul posto ma invece conservato per essere mostrato a comando.
Se applichiamo una template variable a un tag ng-template, questa avrà il tipo TemplateRef.
Abbiamo così introdotto l’ultimo concetto che affronteremo riguardo ai template HTML in Angular, e cioè i riferimenti a template (template reference); questo concetto diventa cruciale per implementare il terzo tipo di direttiva, che non abbiamo ancora approfondito: le direttive strutturali.
CONTENUTI GRATUITI IN EVIDENZA
Guide per aspiranti programmatori 👨🏻🚀
Vuoi muovere i primi passi nel Digital e Tech? Abbiamo preparato alcune guide per aiutarti a orientarti negli ambiti più richiesti oggi.