Il framework Angular è studiato per funzionare come combinazione di elementi atomici chiamati “component”, questi controllano una porzione di schermo denominata “view”, ogni componente è formato da una classe TypeScript, un modello HTML, un foglio di stile CSS e, opzionalmente, da una classe spec di testing. Nel sito ufficiale è possibile trovare maggiori dettagli riguardo a questi elementi di un componente, argomento fondamentale da imparare per poter lavorare in progetti Angular. Per creare un nuovo componente all’interno di un progetto è necessario usare il comando:
ng generate component <nome-componente>
La procedura, senza specifici parametri, costruisce la struttura di default di un componente:
- una cartella chiamata con il nome del componente contenente i quattro file
- una classe TypeScript in un file con estensione ts con la annotation
@Component
- un file html per il modello grafico del componente chiamato template
- un file css per gli stili del componente
- un file di test con estensione
spec.ts
per gli unit-test della classe Typescript
Il comando prevede alcuni parametri opzionali per modificare il comportamento di default, per esempio per evitare la creazione della cartella con il parametro “standalone”, evitare la creazione di un unico file con il parametro “inline-template” ed è possibile usare un parametro per evitare la creazione della classe specifica per i test “skip-test”, un esempio completo di combinazione di questi parametri:
ng generate component <nome-componente-due> --standalone --inline-template --skip-tests
In questo caso il componente è riassunto in unico file TypeScript dove la classe possiede una annotation che definisce il template HTML e gli stili
@Component({ selector: 'app-component-overview', template: '<h1>Hello World!</h1>', styles: ['h1 { font-weight: normal; }'] })
questa tecnica è sconsigliata tranne nel caso di componenti di poche righe. La documentazione ufficiale descrive tutte le caratteristiche impostabili nella annotation component. La struttura standard di un componente senza il parametro inline è:
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-nome-componente', templateUrl: './nome-componente.component.html', styleUrls: ['./nome-componente.component.css'] }) export class NomeComponenteComponent implements OnInit { constructor() { } ngOnInit(): void { } }
il componente presenta il nome selector da usare negli altri per invocare il componente. Quando creato, se non specificato diversamente, il componente viene importato anche nel file “app.modules.ts”, in questo modo tutti i componenti del modulo potranno importare ed usare il componente-tag creato, senza questa importazione il componente non può essere usato. Se in un progetto sono presenti più moduli deve essere importare in tutti i moduli dove il componente deve essere importato, lo scopo di questa tecnica è creare la struttura ad albero dei componenti:
Projection è la tecnica per sviluppare componenti pensati per incastrarsi in maniera nidificata, esistono tre tipi di utilizzo: semplice, multipla o condizionata.
La tecnica Single-slot content projection prevede che un componente venga compreso in un altro in maniera diretta, usando i due componenti di esempio creati sopra il componente in-line può comprendere quello non in-line usando il tag <ng-content>
:
@Component({ selector: 'app-nome-componente-due', template: `<p>nome-componente-due works!</p> <p><ng-content></ng-content></p>`, styleUrls: ['./nome-componente-due.component.css'] }) export class NomeComponenteDueComponent implements OnInit { constructor() { } ngOnInit(): void { } }
Per richiamare il secondo componente nel primo bisogna aggiungerlo nel template:
<p>nome-componente works!</p> <app-nome-componente-due> contenuto del uno passato al componente due </app-nome-componente-due>
La tecnica multipla e la tecnica condizionale sono ben descritti con esempi nel sito ufficiale, queste tecniche sono molto usate nei progetti proprio nella filosofia della struttura ad albero dei componenti, la gestione di dati e degli eventi vengono gestiti con le annotation Input/Output e gli eventEmitter descritti nei prossimi articoli.