Introduzione ai moduli in Angular 4 moduli basati su modelli

Cosa starai creando

I moduli sono fondamentali per qualsiasi applicazione front-end moderna e sono una funzionalità che utilizziamo ogni giorno, anche se non ce ne rendiamo conto. I moduli sono necessari per accedere in sicurezza a un utente all'app, per cercare tutti gli hotel disponibili in una determinata città, prenotare un taxi, creare una lista di cose da fare e fare un sacco di altre cose a cui siamo abituati. Alcune forme hanno solo un paio di campi di input, mentre altri moduli potrebbero avere una matrice di campi che si estendono fino a un paio di pagine o schede. 

In questo tutorial parleremo delle diverse strategie disponibili per lo sviluppo di forme in Angular. Indipendentemente dalla strategia scelta, ecco le cose che una biblioteca di moduli dovrebbe coprire:

  • Supporta l'associazione bidirezionale in modo che i valori di controllo di input siano sincronizzati con lo stato del componente.
  • Tieni traccia dello stato del modulo e utilizza segnali visivi per consentire all'utente di sapere se lo stato corrente è valido o meno. Ad esempio, se il nome utente ha caratteri non validi, dovrebbe apparire un bordo rosso attorno al campo di immissione per il nome utente.
  • Avere un meccanismo per visualizzare correttamente gli errori di convalida.
  • Abilita o disabilita alcune parti del modulo a meno che non vengano soddisfatti alcuni criteri di convalida.

Introduzione alle forme in angolare

Angolare, essendo un vero e proprio framework di front-end, ha il proprio set di librerie per la costruzione di forme complesse. L'ultima versione di Angular ha due potenti strategie di creazione di forme. Loro sono:

  • forme basate su modelli 
  • forme guidate dal modello o reattive

Entrambe le tecnologie appartengono al @ angolari / forme libreria e si basano sulle stesse classi di controllo dei moduli. Tuttavia, differiscono notevolmente nella loro filosofia, nello stile di programmazione e nella tecnica. La scelta dell'uno sull'altro dipende dal tuo gusto personale e anche dalla complessità del modulo che stai cercando di creare. Secondo me, dovresti prima provare entrambi gli approcci e poi sceglierne uno che si adatti al tuo stile e al progetto in questione. 

La prima parte del tutorial riguarderà i moduli basati su modelli con un esempio pratico: creazione di un modulo di registrazione con convalida per tutti i campi modulo. Nella seconda parte di questo tutorial, ripercorreremo i passaggi per creare la stessa forma utilizzando invece un approccio guidato dal modello. 

Moduli basati su modelli

L'approccio basato su modelli è una strategia presa in prestito dall'era AngularJS. Secondo me, è il metodo più semplice per costruire forme. Come funziona? Useremo alcune direttive angolari. 

Le direttive consentono di collegare il comportamento agli elementi nel DOM.
- Documentazione angolare

Angular fornisce direttive specifiche per modulo che è possibile utilizzare per associare i dati di input del modulo e il modello. Le direttive specifiche del modulo aggiungono funzionalità e comportamenti extra a un semplice modulo HTML. Il risultato finale è che il modello si occupa dei valori di associazione con il modello e la convalida del modulo. 

In questo tutorial, utilizzeremo moduli basati su modelli per creare la pagina di registrazione di un'applicazione. Il modulo coprirà gli elementi del modulo più comuni e diversi controlli di convalida su questi elementi del modulo. Ecco i passaggi che seguirai in questo tutorial.

  • Aggiungi FormsModule a app.module.ts.
  • Creare una classe per il modello utente.
  • Creare componenti e layout iniziali per il modulo di registrazione.
  • Utilizzare le direttive di forma angolare come ngModelngModelGroup, e ngForm.
  • Aggiungi la convalida usando i validatori integrati.
  • Mostra errori di convalida in modo significativo.
  • Gestire l'invio del modulo utilizzando ngSubmit.

Iniziamo.

Prerequisiti

Il codice per questo progetto è disponibile sul mio repository GitHub. Scarica il file zip o clona il repository per vederlo in azione. Se preferisci ripartire da zero, assicurati di aver installato la CLI Angolare. Utilizzare il ng comando per generare un nuovo progetto. 

$ ng nuovo SignupFormProject

Quindi, generare un nuovo componente per il SignupForm.

ng genera il componente SignupForm

Sostituisci il contenuto di app.component.html con questo:

 

Ecco la struttura della directory per src / directory. Ho rimosso alcuni file non essenziali per semplificare le cose.

. ├── app │ ├── app.component.css │ ├── app.component.html │ ├── app.component.ts │ ├── app.module.ts │ ├── modulo di iscrizione │ │ ├ ── signup-form.component.css │ │ ├── signup-form.component.html │ │ └── signup-form.component.ts │ └── User.ts ├── index.html ├── main .ts ├── polyfills.ts ├── styles.css ├── tsconfig.app.json └── typings.d.ts 

Come puoi vedere, una directory per il SignupForm componente è stato creato automaticamente. Ecco dove andrà la maggior parte del nostro codice. Ho anche creato un nuovo User.ts per memorizzare il nostro modello utente.

Il modello HTML

Prima di immergerci nel modello di componente reale, abbiamo bisogno di avere un'idea astratta di ciò che stiamo costruendo. Quindi ecco la struttura del modulo che ho nella mia mente. Il modulo di iscrizione avrà diversi campi di input, un elemento select e un elemento checkbox. 


Ecco il modello HTML che utilizzeremo per la nostra pagina di registrazione. 

Modello HTML

 
Iscriviti

Le classi CSS utilizzate nel modello HTML fanno parte della libreria Bootstrap utilizzata per rendere le cose carine. Poiché non si tratta di un tutorial di progettazione, non parlerò molto degli aspetti CSS del modulo, a meno che non sia necessario. 

Impostazione modulo di base

Per utilizzare le direttive del modulo basato su modelli, è necessario importare il file FormsModule a partire dal @ angolari / forme e aggiungilo al importazioni array in app.module.ts.

app / app.module.ts

import FormsModule da '@ angular / forms'; @NgModule (... imports: [BrowserModule, FormsModule], ...) Esporta classe AppModule  

Quindi, crea una classe che includerà tutte le proprietà dell'entità Utente. Possiamo utilizzare un'interfaccia e implementarla nel componente o utilizzare una classe TypeScript per il modello.

app / User.ts

classe di esportazione Utente id: numero; email: string; // Entrambe le password sono in una password per un singolo oggetto: pwd: string; confirmPwd: string; ; genere: stringa; termini: booleano; costruttore (valori: Object = ) // Inizializzazione costruttore Object.assign (this, values);  

Ora, crea un'istanza della classe nel componente SignupForm. Ho anche dichiarato una proprietà aggiuntiva per il genere. 

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

import Component, OnInit da '@ angular / core'; // Importa l'importazione del modello utente Utente da './... / Utente'; @Component (selector: 'app-signup-form', templateUrl: './signup-form.component.html', styleUrls: ['./signup-form.component.css']) classe di esportazione SignupFormComponent implementa OnInit // Proprietà per genere: genere privato: stringa []; // Proprietà per l'utente privato dell'utente: Utente; ngOnInit () this.gender = ['Male', 'Female', 'Others']; // Crea un nuovo oggetto utente this.user = new User (email: "", password: pwd: "", confirm_pwd: "", gender: this.gender [0], terms: false);  

Per il iscrizione-form.component.html file, ho intenzione di utilizzare lo stesso modello HTML discusso sopra, ma con modifiche minori. Il modulo di iscrizione ha un campo di selezione con un elenco di opzioni. Anche se funziona, lo faremo in modo angolare scorrendo la lista usando il comando ngFor direttiva.

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

Iscriviti...
...

Successivamente, vogliamo associare i dati del modulo all'oggetto classe utente in modo che quando si inseriscono i dati di registrazione nel modulo, venga creato un nuovo oggetto Utente che memorizza temporaneamente tali dati. In questo modo, puoi mantenere la vista in sincronia con il modello, e questo è chiamato binding. 

Ci sono un paio di modi per farlo accadere. Lascia che prima ti presenti ngModel e ngForm.

ngForm e ngModel

ngForm e ngModel sono direttive angolari essenziali per la creazione di moduli basati su modelli. Iniziamo con ngForm primo. Ecco un estratto su ngForm dai documenti Angular.

Il NgForm direttiva integra il modulo elemento con funzionalità aggiuntive. Contiene i controlli creati per gli elementi con ngModel direttiva e nome attributo e controlla le loro proprietà, compresa la loro validità. Ha anche il suo valido proprietà che è vera solo se ogni controllo contenuto è valido.

Innanzitutto, aggiorna il modulo con ngForm direttiva:

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

...

#signupForm è una variabile di riferimento del modello che si riferisce al ngForm direttiva che regola l'intera forma. L'esempio seguente dimostra l'uso di a ngForm oggetto di riferimento per la convalida.

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

Qui, signupForm.form.valid restituirà false a meno che tutti gli elementi del modulo non superino i rispettivi controlli di convalida. Il pulsante di invio sarà disabilitato finché il modulo non sarà valido.  

Per quanto riguarda il binding del modello e del modello, ci sono molti modi per farlo, e ngModel ha tre diverse sintassi per affrontare questa situazione. Loro sono:

  1. [(NgModel)] 
  2. [NgModel]
  3. ngModel

Iniziamo con il primo.

Binding a due vie con [(ngModel)]

[(NgModel)] esegue il binding a due vie per leggere e scrivere valori di controllo di input. Se una [(NgModel)] viene utilizzata la direttiva, il campo di input prende un valore iniziale dalla classe di componente associata e lo aggiorna nuovamente ogni volta che viene rilevata qualsiasi modifica al valore di controllo di input (sulla pressione di un tasto e del pulsante). L'immagine seguente descrive meglio il processo di associazione a due vie.

Ecco il codice per il campo di input dell'email:

 

[(ngModel)] = "user.email" associa la proprietà email dell'utente al valore di input. Ho anche aggiunto un nome attributo e set name = "email". Questo è importante e riceverai un errore se non hai dichiarato un attributo name durante l'utilizzo di ngModel. 

Allo stesso modo, aggiungi un [(NgModel)] e un unico nome attributo a ciascun elemento del modulo. Il tuo modulo dovrebbe essere simile a questo ora:

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

... 
...

Il ngModelGroup viene utilizzato per raggruppare campi di moduli simili in modo che possiamo eseguire convalide solo su quei campi modulo. Poiché entrambi i campi della password sono correlati, li inseriremo in un singolo ngModelGroup. Se tutto funziona come previsto, il componente-bound utente la proprietà dovrebbe essere responsabile di memorizzare tutti i valori di controllo del modulo. Per vedere questo in azione, aggiungi quanto segue dopo il tag del modulo:

utente | JSON

Conduci la proprietà dell'utente attraverso il JsonPipe per rendere il modello come JSON nel browser. Questo è utile per il debug e la registrazione. Dovresti vedere un output JSON come questo. 

I valori stanno entrando dalla vista al modello. E il contrario? Prova a inizializzare l'oggetto utente con alcuni valori.

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

this.user = new User (// inizializzato con alcuni dati email: "[email protected]", password: pwd: "", confirm_pwd: "", gender: this.gender [0]);

E compaiono automaticamente nella vista:

"email": "[email protected]", "password": "pwd": "", "confirm_pwd": "", "gender": "Male"

La rilegatura a doppio senso [(NgModel)] la sintassi ti aiuta a costruire le forme senza sforzo. Tuttavia, ha alcuni inconvenienti; quindi, vi è un approccio alternativo che utilizza ngModel o [NgModel].

Aggiunta di ngModel al Mix

quando ngModel viene utilizzato, siamo infatti responsabili dell'aggiornamento della proprietà del componente con i valori di controllo di input e viceversa. I dati di input non fluiscono automaticamente nella proprietà utente del componente.

Quindi sostituire tutte le istanze di [(ngModel)] = "" con ngModel. Terremo il nome attributo perché tutte e tre le versioni di ngModel hanno bisogno del nome attributo a funzionare. 

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

Con ngModel, il valore dell'attributo name diventerà una chiave dell'oggetto di riferimento ngForm signupForm che abbiamo creato in precedenza. Quindi, per esempio, signupForm.value.email memorizzerà il valore di controllo per l'ID e-mail. 

Sostituire utente | JSON con signupForm.value | json perché è lì che tutto lo stato è memorizzato in questo momento. 

Associazione unidirezionale con [ngModel]

Cosa succede se è necessario impostare lo stato iniziale dal componente di classe associato? Questo è ciò che [NgModel] fa per te. 

Qui i dati passano dal modello alla vista. Apporta le seguenti modifiche alla sintassi per utilizzare l'associazione unidirezionale:

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

Quindi quale approccio dovresti scegliere? Se stai usando [(NgModel)] e ngForm insieme, alla fine avrai due stati da mantenere-utente e signupForm.value-e questo potrebbe essere potenzialmente confuso. 

"email": "[email protected]", "password": "pwd": "thisispassword", "confirm_pwd": "thisispassword", "gender": "Male" //user.value " email ":" [email protected] "," password ": " pwd ":" thisispassword "," confirm_pwd ":" thisispassword "," gender ":" Male " //signupForm.value 

Quindi, raccomanderò invece di usare il metodo di associazione unidirezionale. Ma è qualcosa che devi decidere.

Convalida e visualizzazione dei messaggi di errore 

Ecco i nostri requisiti per la convalida.

  • Tutti i controlli di forma sono necessario.
  • Disattiva il pulsante di invio fino a quando non vengono compilati tutti i campi di inserimento.
  • Il campo email deve contenere rigorosamente un ID e-mail.
  • Il campo password deve avere una lunghezza minima di 8.
  • Sia la password che la conferma devono corrispondere.
Il nostro modulo con convalida in vigore

Il primo è facile. Devi aggiungere un necessario attributo di convalida per ogni elemento del modulo come questo:

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

Oltre al necessario attributo, ne ho esportato anche uno nuovo #e-mail variabile di riferimento del modello. In questo modo è possibile accedere al controllo angolare della casella di input all'interno del modello stesso. Lo useremo per visualizzare errori e avvertenze. Ora usa la proprietà disabilitata del pulsante per disabilitare il pulsante:

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

Per aggiungere un vincolo all'e-mail, utilizzare l'attributo pattern che funziona con i campi di input. I pattern sono usati per specificare espressioni regolari come quella seguente:

modello = "[a-z0-9 ._% + -]. + @ [a-z0-9 .-] + \ [a-z] 2,3 $"

Per il campo della password, tutto ciò che devi fare è aggiungere un minlength = "" attributo:

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

 

Per visualizzare gli errori, userò la direttiva condizionale ngIf su un elemento div. Iniziamo con il campo di controllo di input per email:

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

Il campo email non può essere vuoto
L'e-mail id non sembra giusta

C'è molto da fare qui. Iniziamo con la prima riga della sezione errori.

Ricorda il #e-mail variabile che abbiamo esportato in precedenza? Porta una quantità di informazioni sullo stato del controllo di input del campo di posta elettronica. Ciò comprende: email.valid, email.invalid, email.dirty, email.pristine, email.touched, email.untouched, e email.errors.  L'immagine sotto descrive ciascuna di queste proprietà in dettaglio.

Quindi l'elemento div con il * ngIf sarà reso solo se l'email non è valida. Tuttavia, l'utente verrà salutato con errori sui campi di input che sono vuoti anche prima che abbiano la possibilità di modificare il modulo. 

Per evitare questo scenario, abbiamo aggiunto la seconda condizione. L'errore verrà visualizzato solo dopo il controllo è stato visitato o il valore del controllo è stato modificato.

Gli elementi div nidificati vengono utilizzati per coprire tutti i casi di errori di convalida. Noi usiamo email.errors per verificare tutti gli errori di convalida possibili e quindi visualizzarli all'utente sotto forma di messaggi personalizzati. Ora, segui la stessa procedura per gli altri elementi del modulo. Ecco come ho codificato la convalida delle password. 

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

 
La password deve contenere più di 8 caratteri
Le password non corrispondono

Questo sta iniziando a sembrare un po 'disordinato. Angolare ha un set limitato di attributi del validatore: necessario, minlength, lunghezza massima, e modello. Per coprire qualsiasi altro scenario come quello del confronto delle password, dovrai fare affidamento su nidificato ngIf condizionali come ho fatto sopra. O idealmente, crea una funzione di validatore personalizzato, che tratterò nella terza parte di questa serie.

Nel codice sopra, ho usato il ngSe altro sintassi che è stata introdotta nell'ultima versione di Angular. Ecco come funziona:

Contenuto valido ...
Contenuto non valido ...

Invia il modulo utilizzando ngSubmit

Abbiamo quasi finito il modulo. Ora dobbiamo essere in grado di inviare il modulo e il controllo dei dati del modulo deve essere trasferito su un metodo componente, ad esempio onFormSubmit ().

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

...

Ora, per il componente:

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

... public onFormSubmit (valore, valido: valore: utente, valido: booleano) this.user = valore; console.log (this.user); console.log ("valido:" + valido);  ... 

Demo finale

Ecco la versione finale dell'applicazione. Ho aggiunto alcune classi di bootstrap per rendere il modulo carino.

Sommario

Abbiamo finito qui. In questo tutorial, abbiamo trattato tutto ciò che è necessario sapere sulla creazione di un modulo in Angolare utilizzando l'approccio basato sui modelli. Le forme basate su modelli sono popolari per la loro semplicità e facilità d'uso. 

Tuttavia, se è necessario creare un modulo con molti elementi del modulo, questo approccio diventerà disordinato. Quindi, nel prossimo tutorial, tratteremo il modo guidato dal modello per costruire la stessa forma. 

Condividi i tuoi pensieri nei commenti qui sotto.

Scopri JavaScript: la guida completa

Abbiamo creato una guida completa per aiutarti a imparare JavaScript, sia che tu stia appena iniziando come sviluppatore web o che desideri esplorare argomenti più avanzati.