BACK TO THE SERIESGuida galattica ad Angular · 銀河のガイド

Angular in 10 steps - 3 of 10

angular in 10 steps 3 of 10

03 - I componenti: i mattoncini di Angular


Benvenuto nel terzo capitolo! L'ambiente di sviluppo è pronto, quindi da qui in poi si scrive codice. E si parte dal cuore di Angular: i componenti.


Nel primo capitolo ti ho detto che in Angular "tutto ruota attorno ai componenti". Ora ti mostro cosa significa in pratica: alla fine di questo capitolo saprai crearne uno, capire quando ha senso farlo e iniziare a ragionare "a componenti" quando strutturi un'applicazione.


🧩 Cos'è un componente


Un componente è un pezzo riutilizzabile di interfaccia che tiene insieme tre cose:


  • HTML: la struttura
  • CSS: lo stile
  • TypeScript: la logica

L'analogia classica è quella dei LEGO e, per una volta, è anche quella giusta. Ogni mattoncino ha una forma e un colore (HTML e CSS) e alcuni hanno funzionalità speciali (TypeScript). I mattoncini si combinano per costruire cose più grandi, lo stesso pezzo si riusa in punti diversi e, se un tipo di mattoncino va modificato, lo cambi una volta sola e il cambiamento arriva ovunque.


Apri un sito qualsiasi e li vedi subito: l'header con logo e menu, la card prodotto con immagine, prezzo e bottone, il form di contatto, il footer. Ogni elemento che si ripete, o che ha una logica tutta sua, è un buon candidato a diventare componente.


Perché conviene


Te lo riassumo con i motivi che pesano davvero nel lavoro di tutti i giorni:


  • Riutilizzo: scrivi un bottone una volta e lo usi in cinquanta posti
  • Leggibilità: tanti file piccoli e focalizzati invece di un HTML da 500 righe
  • Manutenzione: un bug nella card si sistema in un punto solo
  • Lavoro in team: ognuno sul suo componente, senza pestarsi i piedi
  • Test: ogni pezzo si prova in isolamento, senza tirare su tutta l'app

Quando l'app cresce, aggiungere una funzionalità diventa spesso questione di combinare componenti che hai già.


🔧 Com'è fatto un componente in Angular


In Angular un componente è una classe TypeScript decorata con @Component:

TYPESCRIPT · コード
1import { Component } from '@angular/core';
2
3@Component({
4  selector: 'app-saluto',           // il tag da usare nell'HTML
5  template: `<h1>{{ titolo }}</h1>`, // il template
6  styles: [`h1 { color: rebeccapurple; }`]
7})
8export class SalutoComponent {
9  titolo = 'Il mio primo componente';
10}

I pezzi sono tre:


  1. Il decorator @Component, che dice ad Angular "questa classe è un componente" e ne definisce selector, template e stili
  2. La classe, con le proprietà (i dati) e i metodi (le azioni)
  3. Il template, cioè HTML normale più la sintassi di binding di Angular

Una parola sugli standalone component


Se hai incrociato Angular qualche anno fa, ricorderai che ogni componente andava dichiarato dentro un NgModule, con relativo boilerplate. Dalla versione 14 sono arrivati gli standalone component, componenti indipendenti che importano direttamente ciò che gli serve. E dalla versione 19 gli standalone sono il comportamento predefinito: non serve nemmeno più scrivere standalone: true.


In questa guida usiamo Angular moderno, quindi standalone e basta. Gli NgModule li nomineremo solo quando serviranno a capire codice esistente.

Se un tutorial ti fa dichiarare il componente dentro un NgModule, o insiste su standalone: true, è scritto per una versione vecchia di Angular. Non è sbagliato, ma non è più il modo consigliato di lavorare.

🛠 Creiamo il primo componente


Riprendiamo il progetto del capitolo precedente:

BASH · コード
cd il-mio-primo-progetto
code .

E generiamo un componente con la CLI (la shortcut è ng g c benvenuto):

BASH · コード
ng generate component benvenuto

La CLI crea quattro file:

BASH · コード
1src/app/benvenuto/
2├── benvenuto.component.ts       # la logica
3├── benvenuto.component.html     # il template
4├── benvenuto.component.css      # gli stili
5└── benvenuto.component.spec.ts  # i test

Il file TypeScript generato è già uno standalone component, pronto all'uso:

TYPESCRIPT · コード
1import { Component } from '@angular/core';
2
3@Component({
4  selector: 'app-benvenuto',
5  imports: [],
6  templateUrl: './benvenuto.component.html',
7  styleUrl: './benvenuto.component.css'
8})
9export class BenvenutoComponent {
10
11}

Adesso personalizziamolo. Aggiungiamo un paio di proprietà e due metodi:

TYPESCRIPT · コード
1import { Component } from '@angular/core';
2
3@Component({
4  selector: 'app-benvenuto',
5  imports: [],
6  templateUrl: './benvenuto.component.html',
7  styleUrl: './benvenuto.component.css'
8})
9export class BenvenutoComponent {
10  nome = 'sviluppatore';
11  messaggio = 'Benvenuto nel mondo di Angular!';
12  numeroVisite = 0;
13
14  incrementaVisite() {
15    this.numeroVisite++;
16  }
17
18  cambiaNome(nuovoNome: string) {
19    this.nome = nuovoNome;
20  }
21}

Poi il template, in benvenuto.component.html:

HTML · コード
1<div class="card-benvenuto">
2  <h2>{{ messaggio }}</h2>
3  <p>Ciao <strong>{{ nome }}</strong>!</p>
4  <p>Hai cliccato {{ numeroVisite }} volte.</p>
5
6  <button (click)="incrementaVisite()">Incrementa</button>
7  <button (click)="cambiaNome('Angular developer')">Cambia nome</button>
8</div>

E un minimo di stile in benvenuto.component.css:

CSS · コード
1.card-benvenuto {
2  max-width: 400px;
3  margin: 2rem auto;
4  padding: 2rem;
5  border: 1px solid #ddd;
6  border-radius: 12px;
7  text-align: center;
8}
9
10.card-benvenuto button {
11  margin: 0.5rem 0.25rem 0;
12  padding: 0.5rem 1rem;
13  cursor: pointer;
14}

Il componente esiste, ma nessuno lo sta usando. Apri src/app/app.component.html e sostituisci tutto il contenuto con:

HTML · コード
1<div class="container">
2  <h1>La mia app Angular</h1>
3  <app-benvenuto></app-benvenuto>
4</div>

Ultimo passaggio, quello che all'inizio si dimentica sempre: il componente va importato da chi lo usa. In src/app/app.component.ts:

TYPESCRIPT · コード
1import { Component } from '@angular/core';
2import { BenvenutoComponent } from './benvenuto/benvenuto.component';
3
4@Component({
5  selector: 'app-root',
6  imports: [BenvenutoComponent], // senza questo, il tag non viene riconosciuto
7  templateUrl: './app.component.html',
8  styleUrl: './app.component.css'
9})
10export class AppComponent {
11  title = 'il-mio-primo-progetto';
12}

Avvia il server con ng serve, vai su http://localhost:4200 e gioca con i due bottoni: stai già usando proprietà, eventi e interpolazione senza aver scritto una riga di codice "di collegamento". Questo è il punto di Angular.


🔄 Il data binding, in breve


Nel componente appena scritto abbiamo già usato due tipi di data binding, il meccanismo con cui template e classe si parlano. In tutto sono quattro:


Interpolation {{ }}: mostra il valore di una proprietà nel template

HTML · コード
<h2>{{ messaggio }}</h2>

Event binding (evento): esegue un metodo quando succede qualcosa

HTML · コード
<button (click)="incrementaVisite()">Clicca</button>

Property binding [proprieta]: imposta una proprietà HTML da una proprietà della classe

HTML · コード
<img [src]="urlImmagine" [alt]="descrizione">

Two-way binding [(ngModel)]: tiene sincronizzati un input e una proprietà, nelle due direzioni

HTML · コード
<input [(ngModel)]="nome" placeholder="Il tuo nome">

Per ora ti basta riconoscerli. Al data binding, e ai signals che ti avevo anticipato nel primo capitolo, dedicheremo un capitolo intero più avanti.


Il ciclo di vita di un componente


Ogni componente vive una vita: nasce, reagisce ai cambiamenti e prima o poi viene distrutto. Angular ti permette di agganciarti a questi momenti con i lifecycle hooks, metodi speciali che vengono chiamati automaticamente:


  • ngOnInit() viene eseguito una volta sola, all'inizializzazione: perfetto per caricare dati
  • ngOnChanges() scatta quando cambiano gli input del componente
  • ngOnDestroy() viene chiamato prima della rimozione: il posto giusto per pulire timer e sottoscrizioni
TYPESCRIPT · コード
1import { Component, OnInit, OnDestroy } from '@angular/core';
2
3@Component({ /* ... */ })
4export class MyComponent implements OnInit, OnDestroy {
5  ngOnInit() {
6    console.log('componente inizializzato');
7  }
8
9  ngOnDestroy() {
10    console.log('componente distrutto');
11  }
12}

Non serve impararli tutti adesso. ngOnInit e ngOnDestroy coprono la maggior parte dei casi reali, gli altri li incontreremo strada facendo.


Qualche buona abitudine


Tre regole che mi hanno risparmiato parecchi mal di testa nei progetti veri:


  • Nomi coerenti: file user-card.component.ts, classe UserCardComponent, selector app-user-card. La CLI li genera già così, non combatterla
  • Componenti piccoli: se il template supera le 100 righe, probabilmente dentro ci vivono due o tre componenti che chiedono di uscire
  • Una responsabilità sola: UserCardComponent mostra un utente. Se lo stesso componente mostra la lista, il dettaglio, il form e la validazione, qualcosa è andato storto

I comandi CLI che uso davvero


Oltre a ng g c nome, questi flag tornano utili spesso:

BASH · コード
1# in una sottocartella
2ng g c features/user-profile
3
4# senza file di test
5ng g c mio-comp --skip-tests
6
7# template e stili inline, per componenti minuscoli
8ng g c mio-comp --inline-template --inline-style
9
10# anteprima di cosa verrebbe creato, senza creare nulla
11ng g c mio-comp --dry-run

Il --dry-run in particolare vale oro: prima di generare qualcosa in un progetto grosso, controlli dove andranno a finire i file.


Dove siamo arrivati


Ora sai cos'è un componente, perché è l'unità di misura di qualsiasi app Angular, come crearne uno con la CLI e come collegare dati ed eventi al template. Non è poco: è il modo di ragionare che userai per tutto il resto della guida.


Nel prossimo capitolo entra in scena il Router: trasformeremo i nostri componenti in vere e proprie pagine navigabili, come si aspetta chiunque apra un'applicazione web.