Introduzione ai moduli in Angular 4 Scrittura di validatori di moduli personalizzati

Questa è la terza parte della serie sulla creazione di moduli in Angular. Nei primi due tutorial, abbiamo utilizzato l'approccio basato su modelli e guidato da modelli di Angular per la creazione di moduli. Tuttavia, mentre descrivevo entrambi gli approcci, c'era qualcosa che non coprivamo: funzioni di validazione personalizzate. Questo tutorial coprirà tutto ciò che devi sapere sulla stesura di validatori personalizzati che soddisfano le tue esigenze.

Prerequisiti

Non è necessario aver seguito la prima o la seconda parte di questa serie per la terza parte. Tuttavia, se sei completamente nuovo per le forme in Angular, dovresti andare al primo tutorial di questa serie e iniziare da lì. 

Altrimenti, prendi una copia di questo codice dal nostro repository GitHub e usalo come punto di partenza.  

Validatori integrati

Angular non vanta un'enorme libreria di validatori incorporata. A partire da Angular 4, abbiamo i seguenti validatori popolari in Angular:

  • necessario
  • minlength
  • lunghezza massima
  • modello

Ce ne sono altri ancora e puoi vedere l'elenco completo nei documenti Angular. 

Possiamo utilizzare i suddetti validatori predefiniti in due modi:

1. Come direttive in moduli basati su modelli.

2. Come validatori all'interno del FormControl costruttore in moduli basati su modelli.

name = new FormControl (", Validators.required) 

Se la sintassi di cui sopra non ha senso, segui le mie esercitazioni precedenti sulla creazione di un modulo di iscrizione utilizzando un approccio basato su modelli o un approccio basato sul modello e quindi tornare indietro!

I validatori di moduli incorporati coprono a malapena tutti i casi di utilizzo della convalida che potrebbero essere richiesti in un'applicazione reale. Ad esempio, un modulo di registrazione potrebbe dover verificare se i valori della password e i campi di controllo della password di conferma sono uguali e visualizzare un messaggio di errore se non corrispondono. Un validatore che le e-mail nere da un determinato dominio è un altro esempio comune. 

Ecco un dato di fatto: le forme basate su modelli sono solo forme guidate dal modello sottostante. In un modulo basato sui modelli, lasciamo che il modello si occupi della creazione del modello per noi. La domanda ovvia ora è, come si allega un validatore a un modulo?

I validatori sono solo funzioni. In un modello guidato dal modello, allegare i validatori a FormControl è semplice. In un modulo basato su modelli, tuttavia, c'è ancora un po 'di lavoro da fare. Oltre alla funzione di convalida, sarà necessario scrivere una direttiva per il validatore e creare istanze della direttiva nel modello.

Immersione nei dettagli

Sebbene questo sia già stato trattato, faremo un rapido riassunto del codice per il modulo di registrazione. Innanzitutto, ecco l'approccio reattivo.

app / iscrizione-forma / iscrizione-form.component.ts

 // Usa il formbuilder per costruire il modello Form this.signupForm = this.fb.group (email: [", [Validators.required, Validators.pattern ('[a-z0-9 ._% + -] + @ [a-z0-9 .-] + \. [az] 2,3 $ ')]], password: this.fb.group (pwd: [", [Validators.required, Validators.minLength (8 )]], confirmPwd: [", [Validators.required, Validators.minLength (8)]], validator: PasswordMatch), gender: [", Validators.required],)

FormBuilder è uno zucchero sintassi che crea il FormGroup e FormControl le istanze. UN FormControl tiene traccia del valore e dello stato di convalida di un singolo elemento del modulo. UN FormGroup, d'altra parte, comprende un gruppo di FormControl istanze e tiene traccia del valore e della validità dell'intero gruppo.

Ecco la struttura che abbiamo seguito:

FormGroup -> 'signupForm' FormControl -> 'email' FormGroup -> 'password' FormControl -> 'pwd' FormControl -> 'confirmPwd' FormControl -> 'gender' 

A seconda dei requisiti, possiamo allegare un validatore a a FormControl o a FormGroup. Un validatore di blacklist per e-mail richiederebbe che sia allegato al FormControl istanza dell'email. 

Tuttavia, per convalide più complesse in cui è necessario confrontare e convalidare più campi di controllo, è consigliabile aggiungere la logica di convalida al genitore FormGroup. Come potete vedere, parola d'ordine ha un FormGroup di per sé, e questo rende facile per noi scrivere i validatori che controllano l'uguaglianza di pwd e confirmPwd.

Per il modulo basato sui modelli, tutta la logica va nel modello HTML e qui c'è un esempio:

app / iscrizione-forma / iscrizione-form.component.html

...

ngModel crea un'istanza di FormControl e lo lega a un elemento di controllo del modulo. allo stesso modo, ngModelGroup crea e lega a FormGroup istanza ad un elemento DOM. Condividono la stessa struttura di dominio modello discussa sopra. 

È anche interessante notare che FormControl, FormGroup, e FormArray estendere la AbstractControl classe. Ciò significa che il AbstractControl la classe è responsabile del rilevamento dei valori degli oggetti del modulo, della loro convalida e dell'alimentazione di altri elementi come metodi puliti, sporchi e toccati. 

Ora che conosciamo entrambe le tecniche di form, scriviamo il nostro primo validatore personalizzato.

Funzione di convalida personalizzata per moduli guidati dal modello

I validatori sono funzioni che prendono un FormControl/FormGroup istanza come input e ritorno nullo o un oggetto errore. nullo viene restituito quando la convalida ha esito positivo e, in caso contrario, viene generato l'oggetto errore. Ecco una versione di base di una funzione di convalida. 

app / password match.ts

importare FormGroup da '@ angular / forms'; export function passwordMatch (control: FormGroup): [key: string]: boolean 

Ho dichiarato una funzione che accetta un'istanza di FormGroup come input. Restituisce un oggetto con una chiave di tipo stringa e un valore vero / falso. Questo è così che possiamo restituire un oggetto error del modulo sottostante:

mancata corrispondenza: vero

Successivamente, dobbiamo ottenere il valore di pwd e confirmPwd Istanze di FormControl. Ho intenzione di usare control.get () per prendere i loro valori. 

export function passwordMatch (control: FormGroup): [key: string]: boolean // Grab pwd e confirmPwd utilizzando control.get const pwd = control.get ('pwd'); const confirmPwd = control.get ('confirmPwd');  

Ora dobbiamo fare il confronto e quindi restituire null o un oggetto di errore.

app / password match.ts

import AbstractControl da '@ angular / forms'; export function passwordMatch (control: AbstractControl): [key: string]: boolean // Grab pwd e confirmPwd utilizzando control.get const pwd = control.get ('pwd'); const confirmPwd = control.get ('confirmPwd'); // Se gli oggetti FormControl non esistono, restituisce null se (! Pwd ||! ConfirmPwd) restituisce null; // Se sono effettivamente uguali, restituisce null se (pwd.value === confirmPwd.value) return null;  // Else return false return mismatch: true;  

Perché ho sostituito FormGroup con AbstractControl? Come sai, AbstractControl è la madre di tutte le classi di Form * e ti dà un maggiore controllo sugli oggetti di controllo del modulo. Ha il vantaggio aggiunto che rende il nostro codice di convalida più coerente.

Importa il passwordMatch funzione nel SignupForm componente e dichiararlo come validatore per la password FormGroup esempio.

app / password match.ts

import passwordMatch da './... / password-match'; ... export class SignupFormComponent implementa OnInit ngOnInit () // Usa il formbuilder per costruire il modello Form this.signupForm = this.fb.group (... password: this.fb.group (pwd: [", [Validators.required, Validators.minLength (8)]], confirmPwd: [", [Validators.required, Validators.minLength (8)]], validator: passwordMatch ), ...) 

Visualizzazione degli errori

Se hai fatto tutto bene, password.errors? .mismatch sarà vero ogni volta che i valori di entrambi i campi non corrispondono.

password.errors? .mismatch json

Sebbene ci siano metodi alternativi per visualizzare gli errori, userò il ngIf direttiva per determinare se un messaggio di errore debba essere visualizzato o meno.

Per prima cosa, userò ngIf per vedere se la password non è valida. 

  

Noi usiamo password.touched per garantire che l'utente non sia salutato con errori anche prima che un tasto sia stato premuto.

Successivamente, userò la sintassi ngIf = "expression; then a else b" per visualizzare l'errore corretto.

app / iscrizione-forma / iscrizione-form.component.html

    La password non coincide   La password deve contenere più di 8 caratteri 

Eccolo lì, un modello funzionante del validatore che controlla l'uguaglianza delle password.

Demo per validatori personalizzati in moduli basati su modelli

Direttiva del validatore personalizzato per moduli basati su modelli

Utilizzeremo la stessa funzione di validatore che abbiamo creato per la forma guidata dal modello in precedenza. Tuttavia, non abbiamo accesso diretto alle istanze di FormControl/FormGroup in una forma guidata da un modello. Ecco le cose che devi fare per far funzionare il validatore:

  1. Creare un PasswordMatchDirective che funge da involucro attorno al passwordMatch funzione di validatore. Registreremo la direttiva come validatore usando il NG_VALIDATORS fornitore. Maggiori informazioni su questo più tardi.
  2. Allegare la direttiva al controllo del modulo modello. 

Scriviamo prima la direttiva. Ecco come appare una direttiva in Angular:

app / password match.ts

import AbstractControl da '@ angular / forms'; export function passwordMatch (control: AbstractControl): [key: string]: boolean // Grab pwd e confirmPwd utilizzando control.get const pwd = control.get ('pwd'); const confirmPwd = control.get ('confirmPwd'); // Se gli oggetti FormControl non esistono, restituisce null se (! Pwd ||! ConfirmPwd) restituisce null; // Se sono effettivamente uguali, restituisce null se (pwd.value === confirmPwd.value) return null;  // Else return false return mismatch: true;  // PasswordMatchDirective @Directive (selector: ", providers: []) classe di esportazione PasswordMatchDirective 

Il @Direttiva decoratore è usato per marcare la classe come una direttiva angolare. Accetta un oggetto come argomento che specifica i metadati di configurazione della direttiva, come i selettori per i quali la direttiva deve essere allegata e l'elenco dei provider da iniettare, ecc. Compiliamo i metadati della direttiva:

app / password match.ts

@Directive (selector: '[passwordMatch] [ngModelGroup]', // 1 provider: [// 2 fornire: NG_VALIDATORS, useValue: passwordMatch, multi: true]) classe di esportazione PasswordMatchDirective 
  1. La direttiva è ora allegata a tutti i controlli di input che hanno gli attributi ngModelGroup e passwordMatch
  2. Estendiamo i validatori incorporati usando il NG_VALIDATORS fornitore. Come precedentemente menzionato, NG_VALIDATORS è un fornitore che ha una collezione estensibile di validatori. Il passwordMatch la funzione che abbiamo creato in precedenza è dichiarata come dipendenza. Il multi: vero imposta questo provider come multi-provider. Ciò significa che aggiungeremo alla raccolta esistente di validatori fornita da NG_VALIDATORS.

Ora, aggiungi la direttiva all'array delle dichiarazioni in ngModule.

app / app.module.ts

... import PasswordMatchDirective da './password-match'; @NgModule (dichiarazioni: [AppComponent, SignupFormComponent, PasswordMatchDirective], importa: [BrowserModule, FormsModule], provider: [], bootstrap: [AppComponent]) classe di esportazione AppModule  

Visualizzazione dei messaggi di errore

Per visualizzare i messaggi di errore di convalida, utilizzerò lo stesso modello che abbiamo creato per i moduli basati sul modello.

 
La password non coincide La password deve contenere più di 8 caratteri

Conclusione

In questo tutorial, abbiamo imparato a creare validatori angolari personalizzati per moduli in Angular. 

I validatori sono funzioni che restituiscono null o un oggetto errore. Nei moduli basati su modelli, dobbiamo allegare il validatore a un'istanza FormControl / FormGroup e il gioco è fatto. La procedura era un po 'più complessa in un modulo basato su template perché avevamo bisogno di creare una direttiva sulla parte superiore della funzione validator. 

Se sei interessato a continuare a saperne di più su JavaScript, ricorda di controllare cosa abbiamo in Envato Market.

Spero che questa serie ti sia piaciuta su Forms in Angular. Mi piacerebbe sentire i tuoi pensieri. Condividili attraverso i commenti.