• Skip to primary navigation
  • Skip to main content
  • Skip to footer

Codemotion Magazine

We code the future. Together

  • Discover
    • Events
    • Community
    • Partners
    • Become a partner
    • Hackathons
  • Magazine
    • Backend
    • Dev community
    • Carriere tech
    • Intelligenza artificiale
    • Interviste
    • Frontend
    • DevOps/Cloud
    • Linguaggi di programmazione
    • Soft Skill
  • Talent
    • Discover Talent
    • Jobs
    • Manifesto
  • Companies
  • For Business
    • EN
    • IT
    • ES
  • Sign in
ads

Davide PassafaroLuglio 17, 2024 5 min di lettura

Angular Forms: il nuovo evento unico per i cambiamenti di stato

Frontend
angular reactive forms
facebooktwitterlinkedinreddit

Il rilascio di Angular v18 ha portato una serie di nuove funzionalità e miglioramenti al framework.

Una di queste funzionalità è particolarmente promettente, in quanto introduce una nuova funzionalità all’interno della libreria Angular Forms, aggiungendo nella classe AbstractControl un evento unico per i cambiamenti di stato.

Recommended article
Maggio 26, 2025

10 consigli per diventare esperto di React!

Lucilla Tomassi

Lucilla Tomassi

Frontend

Come di consueto nei miei articoli, prima di approfondire l’argomento principale, ripassiamo un pò le basi. Questo ci aiuterà a comprendere meglio i contenuti dell’articolo.


Angular Reactive Forms: le basi

I Reactive Forms di Angular offrono un approccio basato su classi per gestire gli input dei form, fornendo accesso sincrono al modello di dati, potenti strumenti per la validazione degli input e il tracciamento delle modifiche tramite Observables.

Il modello di dati dei Reactive Forms è composto dalle seguenti classi:

  • FormControl: rappresenta un singolo input del form, il suo valore è una primitiva;
  • FormGroup: rappresenta un gruppo di FormControl, il suo valore è un oggetto;
  • FormArray: rappresenta un elenco di FormControl, il suo valore è un array.

Un esempio comune di un form può essere rappresentato da un FormGroup come questo:

import { FormGroup, FormControl, FormArray } from '@angular/forms';

const articleForm = new FormGroup({
  title: new FormControl(''),
  content: new FormControl(''),
  tags: new FormArray([])
});
Code language: TypeScript (typescript)

Nota: esiste anche la classe FormRecord, un’estensione della classe FormGroup, che permette di creare dinamicamente un gruppo di istanze di FormControl.

Tutte queste classi, d’ora in poi denominate semplicemente controlli, derivano dalla classe AbstractControl e quindi condividono proprietà e metodi comuni.

Template binding

L’approccio basato su classi dei Reactive Forms è supportato da varie direttive fornite dalla stessa libreria, che facilitano l’integrazione dei controlli con gli elementi HTML.

Prendiamo il seguente FormGroup come esempio:

this.articleForm = new FormGroup({
  author: new FormGroup({
    name: new FormControl(''),
  }),
  tags: new FormArray([ new FormControl('Angular') ]),
});
Code language: TypeScript (typescript)

Possiamo facilmente collegarlo al template utilizzando le apposite direttive:

<form [formGroup]="articleForm">
  <div formGroupName="author">
    <input formControlName="name" />
  </div>

  <div formArrayName="tags">
    <div *ngFor="let tag of tags.controls; index as i">
      <input [formControlName]="i" />
    </div>
  </div>
</form>
Code language: HTML, XML (xml)

È importante notare, senza perderci in una spiegazione esaustiva ma fuori dall’ambito di questo articolo, che la FormGroupDirective ci consente di creare facilmente un pulsante per ripristinare il form (reset) e un pulsante per inviare il suo valore (submit):

<form [formGroup]="articleForm">
  <!-- form template -->

  <button type="reset">Clear</button>
  <button type="submit">Save</button>
</form>
Code language: HTML, XML (xml)

La FormGroupDirective intercetta gli eventi di click emessi da questi pulsanti per attivare la funzione reset() del controllo, che riporta il controllo al suo valore iniziale, e l’evento di output ngSubmit della direttiva.

Come restare in ascolto dei cambiamenti

Per restare in ascolto dei cambiamenti di valore ed eseguire logica di business, possiamo sottoscriverci all’observable valueChanges del controllo che desideriamo monitorare:

myControl.valueChanges.subscribe(value => {
  console.log('New value:', value)
});
Code language: TypeScript (typescript)

Disabilitare un controllo

Ogni controllo può essere disabilitato, impedendo agli utenti di modificarne il valore. Questo stato replica il comportamento dell’attributo HTML disabled.

Per realizzare ciò, possiamo creare un controllo già disabilitato oppure utilizzare le funzioni disable() e enable() per attivare e disattivare questo stato:

import { FormControl } from '@angular/forms';

const myControl = new FormControl({ value: '', disabled: true });
console.log(myControl.disabled, myControl.enabled) // true, false

myControl.enable();
console.log(myControl.disabled, myControl.enabled) // false, true

myControl.disable();
console.log(myControl.disabled, myControl.enabled) // true, false
Code language: TypeScript (typescript)

Come possiamo notare nell’esempio in alto, la classe AbstractControl fornisce due proprietà dedicate per descrivere questo stato: disabled e enabled.

Validatori

Per imporre regole specifiche ed assicurarci che i tuoi controlli rispettino determinati criteri, possiamo specificare delle regole di validazione, chiamate anche validatori.

I validatori possono essere sincroni, come required o minLength, oppure asincroni per gestire la validazione che dipendono da risorse esterne:

import { FormControl, Validators } from '@angular/forms';
import { MyCustomAsyncValidators } from './my-custom-async-validators.ts';

const myFormControl = new FormControl('', {
  validators: [ Validators.required, Validators.minLength(3) ],
  asyncValidators: [ MyCustomAsyncValidators.validate ]
});
Code language: TypeScript (typescript)

In base a queste regole, la classe AbstractControl fornisce anche alcune proprietà che descrivono lo stato di validità:

  • valid: un booleano che indica se il valore del controllo ha superato tutti i test delle regole di validazione;
  • invalid: un booleano che indica se il valore del controllo non ha superato tutti i test delle regole di validazione. È l’opposto della proprietà valid;
  • pending: un booleano che indica se il valore del controllo è in fase di verifica di validazione.

FormControlStatus

Sia lo stato disabled che gli stati delle validazioni sono interconnessi.
Infatti, essi derivano dalla proprietà status, la quale è di tipo:

type FormControlStatus = 'VALID' | 'INVALID' | 'PENDING' | 'DISABLED';
Code language: TypeScript (typescript)

Nota: le proprietà valid, invalid, pending, enabled e disabled sono in realtà solo getters derivati dalla proprietà status 🤓

Pristine e Touched

La classe AbstractControl fornisce anche diverse proprietà che descrivono come l’utente ha interagito con il form:

  • pristine: un booleano che indica se il controllo è intatto, il che significa che non è ancora stato modificato;
  • dirty: un booleano che indica se il controllo è stato modificato;
  • untouched: un booleano che indica se il controllo non è ancora stato toccato, il che significa che non è stato ancora interagito con esso;
  • touched: un booleano che indica se il controllo è stato toccato.

Ora che abbiamo ripassato alcuni dei fondamenti dei Reactive Forms, è finalmente giunto il momento di introdurre l’argomento principale di questo articolo.

angular reactive forms meme

Il nuovo evento unico per i cambiamenti di stato

A partire da Angular v18, la classe AbstractControl espone un nuovo observable events per tracciare tutti gli eventi di cambiamento dello stato del form.

Grazie a questo, è possibile monitorare le classi FormControl, FormGroup e FormArray attraverso i seguenti eventi: PristineEvent, ValueChangeEvent, StatusEvent e TouchedEvent.

myControl.events
  .pipe(filter((event) => event instanceof PristineChangeEvent))
  .subscribe((event) => console.log('Pristine:', event.pristine));

myControl.events
  .pipe(filter((event) => event instanceof ValueChangeEvent))
  .subscribe((event) => console.log('Value:', event.value));

myControl.events
  .pipe(filter((event) => event instanceof StatusChangeEvent))
  .subscribe((event) => console.log('Status:', event.status));

myControl.events
  .pipe(filter((event) => event instanceof TouchedChangeEvent))
  .subscribe((event) => console.log('Touched:', event.touched));
Code language: TypeScript (typescript)

Queste capacità sono molto potenti, specialmente perché, a parte il valueChange, in passato non era cosi facile ed immediato tracciare i cambiamenti di stato.

In aggiunta a questo, la classe FormGroup può anche emettere altri due eventi attraverso l’observable events: FormSubmittedEvent e FormResetEvent.

myControl.events
  .pipe(filter((event) => event instanceof FormSubmittedEvent))
  .subscribe((event) => console.log('Submit:', event));

myControl.events
  .pipe(filter((event) => event instanceof FormResetEvent))
  .subscribe((event) => console.log('Reset:', event));
Code language: TypeScript (typescript)

Entrambi gli eventi FormSubmittedEvent e FormResetEvent sono ereditati dalla FormGroupDirective e sono infatti emessi dalla direttiva stessa.

Approfondimenti aggiuntivi

Grazie a questa nuova aggiunta, i seguenti metodi della classe AbstractControl sono stati aggiornati per supportare il parametro emitEvent:

  • markAsPristine(): imposta il controllo come pristine;
  • markAsDirty(): imposta il controllo come dirty;
  • markAsTouched(): imposta il controllo come touched;
  • markAsUntouched(): imposta il controllo come untouched;
  • markAllAsTouched(): imposta il controllo e tutti i suoi discendenti come touched.

Grazie per aver letto questo articolo 🙏

Mi piacerebbe avere qualche feedback quindi grazie in anticipo per qualsiasi commento. 👏

Infine, se ti è piaciuto davvero tanto, condividilo con la tua community. 👋😁

Codemotion Collection Background
Dalla community
Selezionati per te

Vuoi scoprire più articoli come questo? Dai un’occhiata alla collection Dalla community dove troverai sempre nuovi contenuti selezionati dal nostro team.

Share on:facebooktwitterlinkedinreddit

Tagged as:Angular angular forms JavaScript

Davide Passafaro
Cell based architecture, un salto nel buio
Previous Post
La gamification è morta, viva la gamification
Next Post

Footer

Discover

  • Events
  • Community
  • Partners
  • Become a partner
  • Hackathons

Magazine

  • Tech articles

Talent

  • Discover talent
  • Jobs

Companies

  • Discover companies

For Business

  • Codemotion for companies

About

  • About us
  • Become a contributor
  • Work with us
  • Contact us

Follow Us

© Copyright Codemotion srl Via Marsala, 29/H, 00185 Roma P.IVA 12392791005 | Privacy policy | Terms and conditions