Torna a Articoli
Apr 20, 2021
4 min read

Genera le reactive forms con RxFormMapper

In questo articolo, ti spiegherò come evitare di perdere tempo costruendo e assegnando i tuoi moduli reattivi tramite RxFormMapper.

Jack, il mio gatto, che guarda curiosamente le pagine di un libro aperto

Cos’è RxFormMapper? RxFormMapper è una libreria sviluppata per Angular che permette di convertire, tramite annotazioni, classi in reactive form e viceversa.

Quando usare RxFormMapper?

A volte hai bisogno di trasformare le classi che hai in reactive form. Ad esempio, supponiamo che tu abbia un modello utente che vuoi compilare tramite un modulo:

export class User {
	name: string;
	surname: string;
	age: number;
}

Cosa fare quindi? Come creo un form utente? La soluzione classica è creare manualmente delle istanze di Reactive Form e assegnare ogni proprietà del tuo modello ai vari controller.

new FormGroup(
	name: new FormControl(user.name),
	surname: new FormControl(user.surname),
	age: new FormControl(user.age),
);

Tuttavia, le cose possono complicarsi rapidamente con gerarchie di oggetti più complesse.

Per evitare tutto questo, puoi utilizzare RxFormMapper:

export class User {
	@FormControl()
	name: string;
	@FormControl()
	surname: string;
	@FormControl()
	age: number;
}

Perché usare RxFormMapper? RxFormMapper accelera lo sviluppo dei tuoi form evitando boilerplate ridondante nel codice. I principali vantaggi sono:

  • Zero configurazione: tramite annotazioni elimina il boilerplate per creare e assegnare i form.
  • Dependency Injection: RxFormMapper sfrutta il container DI di Angular per risolvere i validator e i custom mapper.
  • Custom mapper: Se vuoi creare form personalizzati per campi specifici, puoi farlo facilmente con il decoratore @CustomControl.

Iniziamo a scrivere codice

Installiamo il pacchetto npm

npm i rx-form-mapper --save

reflect-metadata è necessario (con Angular+ dovresti già avere questa dipendenza installata).

npm i reflect-metadata --save

Includiamo il modulo

Importiamo RxFormMapperModule nel tuo AppModule

// app.module.ts
import { RxFormMapperModule } from 'rx-form-mapper';

@NgModule({
  imports: [RxFormMapperModule.forRoot()],
})
export class AppModule { }

Definiamo il modello

// user-registration.model.ts
export class UserRegistration {
  public name: string;
  public surname: string;
  public birthday: Date;
  public email: string;
  public password: string;
  public passwordCheck: string;
}

Annotiamolo

RxFormMapper ti consente di specificare tramite annotazioni il tipo di AbstractControl per ogni campo nel tuo modello: FormControl, FormGroup e FormArray.

// user-registration.model.ts
import { Validators } from '@angular/forms';
import { FormControl, Form } from 'rx-form-mapper';
import { AlreadySignedAsyncValidator, noWhitespace, passwordCheck } from './app-validators';

@Form({validators: passwordCheck })
export class UserRegistration {
  @FormControl({ validators: noWhitespace })
  public name: string;

  @FormControl({ validators: noWhitespace })
  public surname: string;

  @FormControl({ validators: Validators.required })
  public birthday: Date;

  @FormControl({ 
    validators: [Validators.required, Validators.email],
    asyncValidators: AlreadySignedAsyncValidator 
  })
  public email: string;

  @FormControl({ validators: noWhitespace })
  public password: string;

  @FormControl({ validators: noWhitespace })
  public passwordCheck: string;
}

Puoi trovare ulteriori informazioni sulle annotazioni di RxFormMapper consultando la pagina GitHub indicata all’inizio di questo articolo.

Aspetta… AsyncValidators? Come inietti i servizi?!

Non preoccuparti: RxFormMapper risolve automaticamente tutti i validator registrati all’interno del container Angular per te! 😉

// already-signed-async.validator.ts
@Injectable()
export class AlreadySignedAsyncValidator implements AsyncValidator {
  
  public constructor(private readonly http: HttpClient) {}

  validate(control: AbstractControl): Promise<ValidationErrors>|Observable<ValidationErrors> {
    if (isWhitespace(control.value)) {
      return of(null);
    }

    return http.get<>('your url').pipe(
      map(exists => exists ? ({ alreadySigned: true }) : null)
    );
  }
}
// app.module.ts
import { RxFormMapperModule } from 'rx-form-mapper';
import { AlreadySignedAsyncValidator } from './validators';

@NgModule({
  imports: [RxFormMapperModule.forRoot()],
  providers: [AlreadySignedAsyncValidator]
})
export class AppModule { }

Costruiamo il nostro form

// app.component.ts
import { Component } from "@angular/core";
import { FormGroup } from "@angular/forms";
import { RxFormMapper } from "rx-form-mapper";
import { UserRegistration } from "./user-registration";

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {

  public readonly form: FormGroup;

  public constructor(mapper: RxFormMapper) {
    this.form = mapper.writeForm(new UserRegistration());
  }
  
}

Puoi trovare il codice sorgente di questo articolo su stackblitz 😁

Conclusioni

RxFormMapper è uno strumento fantastico che ti consente di creare reactive form in modo semplice e dichiarativo tramite le annotazioni, permettendoti di concentrarti sulle tue funzionalità. Questo tipo di framework è particolarmente adatto per applicazioni basate su CRUD, poiché riduce drasticamente il codice da mantenere.

Se questa guida ti è stata utile, non dimenticare di condividerla con chiunque potrebbe trarne beneficio 😃

So long, and thanks for all the fish 🐬