Dette er den tredje delen av serien om å skape former i Angular. I de to første opplæringen brukte vi Angular sin mal-drevne og modelldrevne tilnærming til å lage skjemaer. Men mens du detaljerte begge tilnærmingene, var det noe vi ikke dekker - tilpassede valideringsfunksjoner. Denne opplæringen vil dekke alt du trenger å vite om å skrive tilpassede validatorer som oppfyller dine krav.
Du trenger ikke å følge del 1 eller 2 i denne serien for del tre for å gi mening. Men hvis du er helt ny til skjemaer i Angular, bør du gå over til den første opplæringen i denne serien og starte derfra.
Ellers ta en kopi av denne koden fra vår GitHub repo og bruk det som utgangspunkt.
Angular har ikke et stort innebygd validatorbibliotek. Fra Angular 4 har vi følgende populære validatorer i Angular:
Det er faktisk noen få flere, og du kan se hele listen i Angular docs.
Vi kan bruke de ovennevnte innebygde validatorene på to måter:
1. Som direktiver i mal-drevne former.
2. Som validatorer inne i FormControl
konstruktør i modelldrevne former.
name = new FormControl (", Validators.required)
Hvis synspunktet ovenfor ikke gir mening, følger du mine tidligere veiledninger om å bygge et registreringsskjema ved hjelp av en malstyrt tilnærming eller en modelldrevet tilnærming, og deretter slippe tilbake!
De innebygde skjemavalidatorene dekker ikke alle de valideringsbrukstilfeller som kan være påkrevd i en virkelig applikasjon. For eksempel kan et registreringsskjema kanskje sjekke om verdiene til passordet og bekreft passordkontrollfeltene er like og viser en feilmelding hvis de ikke samsvarer. En validator som svartelister e-post fra et bestemt domene er et annet vanlig eksempel.
Her er et faktum: Template-drevne skjemaer er bare modelldrevne skjemaer under. I en mal-drevet form lar vi malen ta vare på modellopprettelsen for oss. Det åpenbare spørsmålet nå er, hvordan legger du til en validator i et skjema?
Validatorer er bare funksjoner. I en modelldrevet form er vedlegg av validatorer til FormControl rettferdig. I en mal-drevet form er det imidlertid litt mer arbeid å gjøre. I tillegg til validatorfunksjonen må du skrive et direktiv for validatoren og opprette forekomster av direktivet i malen.
Selv om dette allerede er dekket, vil vi gå gjennom en rask omtale av koden for registreringsskjemaet. Først, her er den reaktive tilnærmingen.
// Bruk formbyggeren til å bygge Form-modellen this.signupForm = this.fb.group (email: [", [Validators.required, Validators.pattern ('[a-z0-9 ._% + -] + @ [a-z0-9 .-] + \. [az] 2,3 $ ')]], passord: this.fb.group (pwd: [", [Validators.required, Validators.minLength )], bekreftePwd: [", [Validators.required, Validators.minLength (8)]], validator: PasswordMatch), kjønn: [" Validators.required ",)
FormBuilder
er en syntaks sukker som skaper FormGroup
og FormControl
forekomster. EN FormControl
sporer verdien og valideringsstatusen til et enkelt formelement. EN FormGroup
, på den annen side, omfatter en gruppe av FormControl
forekomster, og det sporer verdien og gyldigheten av hele gruppen.
Her er strukturen som vi har fulgt:
FormGroup -> 'signupForm' FormControl -> 'email' FormGroup -> 'passord' FormControl -> 'pwd' FormControl -> 'confirmPwd' FormControl -> 'gender'
Avhengig av kravene, kan vi legge ved en validator til en FormControl
eller a FormGroup
. En e-post blacklisting validator ville kreve at den ble festet til FormControl
forekomst av e-posten.
Men for mer komplekse valideringer der flere kontrollfelt må sammenlignes og validert, er det en bedre ide å legge til valideringslogikken for foreldrene FormGroup
. Som du kan se, passord
har en FormGroup
av seg selv, og dette gjør det enkelt for oss å skrive validatorer som kontrollerer likestilling av pwd
og confirmPwd
.
For det malformede skjemaet går all den logikken inn i HTML-malen, og her er et eksempel:
ngModel
skaper en forekomst av FormControl
og binder den til et skjemakontrollelement. på samme måte, ngModelGroup
skaper og binder en FormGroup
eksempel på et DOM-element. De deler samme modelldomenestruktur som diskutert ovenfor.
Det er også interessant å merke seg det FormControl
, FormGroup
, og FormArray
utvide AbstractControl
klasse. Hva dette betyr er at AbstractControl
klassen er ansvarlig for å spore verdiene for skjemobjekter, validere dem og drive andre ting som uberørte, skitne og berørte metoder.
Nå som vi er kjent med både formteknikkene, la oss skrive vår første tilpassede validator.
Validatorer er funksjoner som tar en FormControl
/FormGroup
eksempel som input og returnere heller null
eller et feilobjekt. null
returneres når valideringen er vellykket, og hvis ikke, blir feilobjektet kastet. Her er en veldig grunnleggende versjon av en valideringsfunksjon.
importer FormGroup fra '@ vinkel / former'; eksportfunksjon passordMatch (kontroll: FormGroup): [nøkkel: streng]: boolsk
Jeg har erklært en funksjon som aksepterer en forekomst av FormGroup
som en inngang. Den returnerer et objekt med en nøkkel av typen streng og en ekte / falsk verdi. Dette er slik at vi kan returnere et feilobjekt av skjemaet nedenfor:
mismatch: true
Deretter må vi få verdien av pwd
og confirmPwd
FormControl-forekomster. Jeg skal bruke control.get ()
å hente sine verdier.
eksportfunksjon passordMatch (kontroll: FormGroup): [nøkkel: streng]: boolsk // Grab pwd og confirmPwd ved hjelp control.get const pwd = control.get ('pwd'); const confirmPwd = control.get ('confirmPwd');
Nå må vi gjøre sammenligningen og returnere enten null eller et feilobjekt.
importer AbstractControl fra '@ angular / forms'; eksportfunksjon passwordMatch (kontroll: AbstractControl): [nøkkel: streng]: boolean // Grab pwd og confirmPwd ved hjelp control.get const pwd = control.get ('pwd'); const confirmPwd = control.get ('confirmPwd'); // Hvis FormControl-objekter ikke eksisterer, return null hvis (! Pwd ||! ConfirmPwd) returnere null; // Hvis de faktisk er like, returner null hvis (pwd.value === confirmPwd.value) return null; // Else returnere falsk retur mismatch: true;
Hvorfor erstattet jeg FormGroup
med AbstractControl
? Som du vet, AbstractControl
er mor til alle Form * klasser, og det gir deg mer kontroll over formkontrollobjektene. Det har den ekstra fordelen at den gjør vår valideringskode mer konsistent.
Importer passwordMatch
fungere i SignupForm
komponent og erklære det som en validator for passordet FormGroup
forekomst.
importere passwordMatch fra './.../password-match'; ... eksportklasse SignupFormComponent implementerer OnInit ngOnInit () // Bruk formbuilderen til å bygge Form-modellen this.signupForm = this.fb.group (... passord: this.fb.group (pwd: [", [Validators.required, Validators.minLength (8)]], confirmPwd: [", [Validators.required, Validators.minLength (8)]], validator: passwordMatch ), ...)
Hvis du gjorde alt riktig, password.errors? .mismatch
vil være sant når verdiene til begge feltene ikke stemmer overens.
password.errors? .mismatch json
Selv om det finnes alternative måter å vise feil på, skal jeg bruke ngIf
direktiv for å avgjøre om en feilmelding skal vises eller ikke.
Først skal jeg bruke ngIf
for å se om passordet er ugyldig.
Vi bruker password.touched
for å sikre at brukeren ikke blir møtt med feil selv før en tast er trykket.
Deretter skal jeg bruke ngIf = "uttrykket, så en annen b" syntaks for å vise den riktige feilen.
Passordet stemmer ikke overens Passordet må være over 8 tegn
Der har du det, en fungerende modell av validatoren som sjekker om likestilling av passord.
Vi bruker den samme validatorfunksjonen som vi opprettet for det modelldrevne skjemaet tidligere. Vi har imidlertid ikke direkte tilgang til forekomster av FormControl
/FormGroup
i en mal-drevet form. Her er de tingene du må gjøre for å få validatoren til å fungere:
PasswordMatchDirective
som fungerer som en wrapper rundt passwordMatch
validator funksjon. Vi registrerer direktivet som en validator ved hjelp av NG_VALIDATORS
forsørger. Mer om dette senere.La oss skrive direktivet først. Slik ser et direktiv ut i Angular:
importer AbstractControl fra '@ angular / forms'; eksportfunksjon passwordMatch (kontroll: AbstractControl): [nøkkel: streng]: boolean // Grab pwd og confirmPwd ved hjelp control.get const pwd = control.get ('pwd'); const confirmPwd = control.get ('confirmPwd'); // Hvis FormControl-objekter ikke eksisterer, return null hvis (! Pwd ||! ConfirmPwd) returnere null; // Hvis de faktisk er like, returner null hvis (pwd.value === confirmPwd.value) return null; // Else returnere falsk retur mismatch: true; // PasswordMatchDirective @Directive (selector: ", leverandører: []) eksportklasse PasswordMatchDirective
De @Directive
dekoratør brukes til å markere klassen som et vinkeldirektiv. Den aksepterer et objekt som et argument som spesifiserer direktivkonfigurasjonsmetadataene, for eksempel valggivere som direktivet skal festes til, og listen over leverandører som skal injiseres, etc. La oss fylle ut metadataene i direktivet:
@Directive (selector: '[passwordMatch] [ngModelGroup]', // 1 leverandører: [// 2 provide: NG_VALIDATORS, useValue: passwordMatch, multi: true]) eksportklasse PasswordMatchDirective
ngModelGroup
og passwordMatch
. NG_VALIDATORS
forsørger. Som tidligere nevnt, NG_VALIDATORS
er en leverandør som har en utvidbar samling av validatorer. De passwordMatch
funksjonen som vi opprettet tidligere blir erklært som en avhengighet. De multi: sant
Setter denne leverandøren til å være en multi-leverandør. Hva dette betyr er at vi vil legge til den eksisterende samlingen av validatorer levert av NG_VALIDATORS
.Nå legger du til direktivet i deklarasjonene i ngModule
.
... importere PasswordMatchDirective fra './password-match'; @NgModule (declarations: [AppComponent, SignupFormComponent, PasswordMatchDirective], import: [BrowserModule, FormsModule], leverandører: [], bootstrap: [AppComponent]) eksportklasse AppModule
For å vise valideringsfeilmeldingene, skal jeg bruke den samme malen som vi opprettet for modelldrevne skjemaer.
Passordet stemmer ikke overens Passordet må være over 8 tegn
I denne opplæringen lærte vi om å skape egendefinerte Angular validators for skjemaer i Angular.
Validators er funksjoner som returnerer null eller et feilobjekt. I modelldrevne skjemaer må vi legge til validatoren til en FormControl / FormGroup-forekomst, og det er det. Prosedyren var litt mer kompleks i en mal-drevet form, fordi vi trengte å lage et direktiv på toppen av validatorfunksjonen.
Hvis du er interessert i å fortsette å lære mer om JavaScript, husk å sjekke ut hva vi har i Envato Market.
Jeg håper at du har hatt glede av denne serien på Forms in Angular. Jeg vil gjerne høre tankene dine. Del dem gjennom kommentarene.