Detta är den tredje delen av serien om att skapa former i Angular. I de två första handledningarna använde vi Angular's mall-driven och modelldriven metod för att skapa former. Men när vi redogjorde för båda tillvägagångssätten fanns det något som vi inte täckte - anpassade valideringsfunktioner. Denna handledning kommer att täcka allt du behöver veta om att skriva anpassade validatorer som uppfyller dina krav.
Du behöver inte ha följt del en eller två i den här serien för att del tre ska vara meningsfull. Men om du är helt ny på formulär i Angular, bör du gå vidare till den första handledningen i den här serien och börja därifrån.
I annat fall ta en kopia av den här koden från vårt GitHub repo och använd det som utgångspunkt.
Angular pryder inte ett stort inbyggt validatorbibliotek. Från Angular 4 har vi följande populära validatorer i Angular:
Det finns faktiskt några fler, och du kan se hela listan i Angular docs.
Vi kan använda ovanstående inbyggda validatorer på två sätt:
1. Som direktiv i mallstyrda former.
2. Som validerare inne i FormControl
konstruktör i modelldrivna former.
name = new FormControl (", Validators.required)
Om ovanstående syntax inte är meningsfull följer du mina tidigare handledning om att skapa en registreringsblankett med hjälp av en mallstyrd strategi eller modelldriven strategi och sedan släppa tillbaka!
De inbyggda formulärvaliderna täcker knappast alla valideringsanvändningsfall som kan krävas i en verklig applikation. Till exempel kan en anmälningsblankett behöva kontrollera om värdena på lösenordet och bekräfta lösenordskontrollfälten är lika och visa ett felmeddelande om de inte matchar. En validator som svartlistor e-postmeddelanden från en viss domän är ett annat vanligt exempel.
Här är ett faktum: Mallformade former är bara modelldrivna former under. I en mallstyrd form låter vi mallen ta hand om modellskapandet för oss. Den uppenbara frågan nu är hur du bifogar en validerare till en blankett?
Validatorer är bara funktioner. I en modelldriven form är bifogade validatorer till FormControl okomplicerad. I en mallstyrd form är det emellertid lite mer arbete att göra. Förutom valideringsfunktionen måste du skriva ett direktiv för validatorn och skapa instanser av direktivet i mallen.
Även om detta redan har blivit täckt, kommer vi att gå igenom ett snabbt sammanfattning av koden för registreringsformuläret. Först här är det reaktiva tillvägagångssättet.
// Använd formverktyget för att bygga formulärmodellen this.signupForm = this.fb.group (email: [", [Validators.required, Validators.pattern ('[a-z0-9 ._% + -] + @ [a-z0-9 .-] + \. [az] 2,3 $ ')]], lösenord: this.fb.group (pwd: [", [Validators.required, Validators.minLength )], bekräftaPwd: [", [Validators.required, Validators.minLength (8)]], validator: PasswordMatch), kön: [" Validators.required ",)
FormBuilder
är ett syntaksocker som skapar FormGroup
och FormControl
instanser. en FormControl
spårar värdet och valideringsstatusen för ett enskilt formelement. en FormGroup
, å andra sidan innefattar en grupp av FormControl
instanser, och det spårar värdet och giltigheten för hela gruppen.
Här är den struktur som vi har följt:
FormGroup -> 'signupForm' FormControl -> 'email' FormGroup -> 'lösenord' FormControl -> 'pwd' FormControl -> 'confirmPwd' FormControl -> 'gender'
Beroende på kraven kan vi bifoga en validator till en FormControl
eller a FormGroup
. En blacklisting-validator för e-post skulle kräva att den bifogas FormControl
Exempel på e-postmeddelandet.
För mer komplicerade valideringar där flera kontrollfält måste jämföras och valideras är det emellertid en bättre idé att lägga till valideringslogiken till föräldern FormGroup
. Som du kan se, Lösenord
har en FormGroup
av sig själv, och det gör det lätt för oss att skriva validatorer som kontrollerar jämlikheten hos pwd
och confirmPwd
.
För den mallstyrda formen går all den logiken in i HTML-mallen, och här är ett exempel:
ngModel
skapar en förekomst av FormControl
och binder den till ett formkontrollelement. Liknande, ngModelGroup
skapar och binder en FormGroup
instans till ett DOM-element. De delar samma modelldomänstruktur som diskuterats ovan.
Det är också intressant att notera det FormControl
, FormGroup
, och FormArray
utöka AbstractControl
klass. Vad det här betyder är att AbstractControl
klassen ansvarar för att spåra värdena på formobjekt, validera dem och driva andra saker som orörda, smutsiga och rörda metoder.
Nu när vi är bekanta med både formteknikerna, låt oss skriva vår första anpassade validator.
Validatorer är funktioner som tar en FormControl
/FormGroup
Exempel som inmatning och retur heller null
eller ett felobjekt. null
returneras när valideringen är framgångsrik, och om inte, kastas felobjektet. Här är en mycket grundläggande version av en valideringsfunktion.
importera FormGroup från '@ vinkel / formulär'; exportfunktion passwordMatch (kontroll: FormGroup): [nyckel: sträng]: boolean
Jag har förklarat en funktion som accepterar en förekomst av FormGroup
som en inmatning. Det returnerar ett objekt med en nyckel av typsträng och ett sannt / falskt värde. Det här är så att vi kan returnera ett felobjekt av formuläret nedan:
mismatch: true
Därefter måste vi få värdet av pwd
och confirmPwd
FormControl instanser. Jag ska använda control.get ()
att hämta sina värden.
exportfunktion passwordMatch (kontroll: FormGroup): [nyckel: sträng]: boolean // Hämta pwd och confirmPwd med control.get const pwd = control.get ('pwd'); const confirmPwd = control.get ('confirmPwd');
Nu behöver vi göra jämförelsen och returnera antingen null eller ett felobjekt.
importera AbstractControl från '@ vinkel / former'; exportfunktion passwordMatch (kontroll: AbstractControl): [nyckel: sträng]: boolean // Hämta pwd och confirmPwd med control.get const pwd = control.get ('pwd'); const confirmPwd = control.get ('confirmPwd'); // Om FormControl-objekt inte existerar, returnera null om (! Pwd ||! ConfirmPwd) returnera null; // Om de verkligen är lika, returnera null om (pwd.value === confirmPwd.value) return null; // Else returnerar falsk retur mismatch: true;
Varför ersatte jag? FormGroup
med AbstractControl
? Som du vet, AbstractControl
är moder till alla Form * -klasser, och det ger dig mer kontroll över formkontrollobjekten. Det har den extra fördelen att det gör vår valideringskod mer konsekvent.
Importera passwordMatch
funktion i SignupForm
komponent och förklara det som en validator för lösenordet FormGroup
exempel.
importera passwordMatch från './.../password-match'; ... exportklass SignupFormComponent implementerar OnInit ngOnInit () // Använd formverktyget för att bygga formulärmodellen this.signupForm = this.fb.group (... lösenord: this.fb.group (pwd: [", [Validators.required, Validators.minLength (8)]], bekräftaPwd: [", [Validators.required, Validators.minLength (8)]], validator: passwordMatch ), ...)
Om du gjorde allt rätt, password.errors? .mismatch
kommer att vara sant när värdena för båda fälten inte matchar.
password.errors? .mismatch json
Även om det finns alternativa sätt att visa fel, kommer jag att använda ngIf
direktivet för att avgöra om ett felmeddelande ska visas eller inte.
Först ska jag använda ngIf
för att se om lösenordet är ogiltigt.
Vi använder password.touched
för att säkerställa att användaren inte hälsas med fel redan innan en tangent har tryckts.
Därefter kommer jag att använda ngIf = "expression, sedan en annan b" -syntax för att visa rätt fel.
Lösenordet matchar inte Lösenordet måste vara mer än 8 tecken
Där har du det, en arbetsmodell av validatorn som kontrollerar lösenordslikhet.
Vi använder samma validatorfunktion som vi skapade för den modelldrivna formen tidigare. Vi har emellertid inte direkt tillgång till instanser av FormControl
/FormGroup
i en mall-driven form. Här är de saker du behöver göra för att validatorn ska fungera:
PasswordMatchDirective
som fungerar som ett omslag runt passwordMatch
valideringsfunktion. Vi kommer att registrera direktivet som en validator med hjälp av NG_VALIDATORS
leverantören. Mer om detta senare.Låt oss skriva direktivet först. Så här ser ett direktiv ut i Angular:
importera AbstractControl från '@ vinkel / former'; exportfunktion passwordMatch (kontroll: AbstractControl): [nyckel: sträng]: boolean // Hämta pwd och confirmPwd med control.get const pwd = control.get ('pwd'); const confirmPwd = control.get ('confirmPwd'); // Om FormControl-objekt inte existerar, returnera null om (! Pwd ||! ConfirmPwd) returnera null; // Om de verkligen är lika, returnera null om (pwd.value === confirmPwd.value) return null; // Else returnerar falsk retur mismatch: true; // PasswordMatchDirective @Directive (selector: ", leverantörer: []) export klass PasswordMatchDirective
De @Direktiv
dekoratorn används för att markera klassen som ett vinkeldirektiv. Den accepterar ett objekt som ett argument som anger direktivets konfigurationsmetodata, såsom valörer för vilka direktivet ska bifogas, och listan över leverantörer som ska injiceras etc. Låt oss fylla i direktivet metadata:
@Directive (selector: '[passwordMatch] [ngModelGroup]', // 1 leverantörer: [// 2 provide: NG_VALIDATORS, useValue: passwordMatch, multi: true]) exportklass PasswordMatchDirective
ngModelGroup
och passwordMatch
. NG_VALIDATORS
leverantören. Som tidigare nämnt, NG_VALIDATORS
är en leverantör som har en omfattande samling av validatorer. De passwordMatch
Funktionen som vi skapade tidigare förklaras som ett beroende. De multi: true
sätter denna leverantör till en multi-leverantör. Vad detta innebär är att vi kommer att lägga till den befintliga samlingen av validatorer som tillhandahålls av NG_VALIDATORS
.Lägg nu till direktivet i deklarationsmatrisen ngModule
.
... importera PasswordMatchDirective från './password-match'; @NgModule (deklarationer: [AppComponent, SignupFormComponent, PasswordMatchDirective], import: [BrowserModule, FormsModule], leverantörer: [], bootstrap: [AppComponent]) exportklass AppModule
För att visa valideringsfelmeddelandena ska jag använda samma mall som vi skapade för de modelldrivna formulären.
Lösenordet matchar inte Lösenordet måste vara mer än 8 tecken
I denna handledning lärde vi oss om att skapa anpassade vinkelvaliderare för formulär i Angular.
Validatorer är funktioner som returnerar null eller ett felobjekt. I modelldrivna former måste vi bifoga validatorn till en FormControl / FormGroup-förekomst, och det är det. Förfarandet var lite mer komplext i en mallstyrd form eftersom vi behövde skapa ett direktiv ovanpå valideringsfunktionen.
Om du är intresserad av att fortsätta lära dig mer om JavaScript, kom ihåg att kolla vad vi har på Envato Market.
Jag hoppas att du har haft den här serien på Forms in Angular. Jag skulle gärna höra dina tankar. Dela dem genom kommentarerna.