Blanketter är kritiska för alla moderna applikationer, och de är en funktion som vi använder varje dag, även om vi inte inser det. Blanketter krävs för att logga in säkert på en användare till appen, leta efter alla tillgängliga hotell i en viss stad, boka en hytt, bygga en att göra-lista och göra massor av andra saker som vi är vana vid. Vissa former har bara några inmatningsfält, medan andra former kan ha en rad fält som sträcker sig till ett par sidor eller flikar.
I denna handledning kommer vi att prata om olika strategier som är tillgängliga för att utveckla former i Angular. Oavsett vilken strategi du väljer, här är de saker som ett formulärbibliotek bör täcka:
Angular, som är en fullfjädrad fronten-ram, har sin egen uppsättning bibliotek för att bygga komplexa former. Den senaste versionen av Angular har två kraftfulla formbyggnadsstrategier. Dom är:
Båda teknologierna hör till @ kantiga / former
biblioteket och bygger på samma formkontrollklasser. Men de skiljer sig anmärkningsvärt i sin filosofi, programmeringsstil och teknik. Att välja den ena över den andra beror på din personliga smak och på komplexiteten i den form som du försöker skapa. Enligt min mening borde du prova båda metoderna först och välj sedan en som passar din stil och projektet för hand.
Den första delen av handledningen kommer att omfatta mallstyrda blanketter med ett praktiskt exempel: Skapa en anmälningsblankett med validering för alla formulärfält. I den andra delen av denna handledning återfår vi stegen för att skapa samma form med hjälp av en modelldriven inriktning istället.
Den mallstyrda strategin är en strategi som lånades från AngularJS-tiden. Enligt min mening är det den enklaste metoden för att bygga former. Hur fungerar det? Vi kommer att använda några Angular Directives.
Direktiv ger dig möjlighet att bifoga beteende till element i DOM.
- Angular Documentation
Angular ger formulärspecifika direktiv som du kan använda för att binda formulärinmatningsdata och modell. De formspecifika direktiven lägger till extra funktionalitet och beteende till en vanlig HTML-form. Slutresultatet är att mallen tar hand om bindande värden med modellen och formvalideringen.
I den här handledningen använder vi mallstyrda formulär för att skapa anmälningssidan för en applikation. Formuläret kommer att täcka de vanligaste formulärelementen och olika valideringskontroller av dessa formulärelement. Här är de steg du följer i denna handledning.
app.module.ts
.ngModel
, ngModelGroup
, och ngForm
.ngSubmit
.Låt oss börja.
Koden för detta projekt finns på min GitHub repo. Ladda ner zip eller klon repo för att se den i åtgärd. Om du föredrar att börja från början istället, se till att du har installerat Angular CLI. Använd ng
kommando för att skapa ett nytt projekt.
$ ng nytt SignupFormProject
Skapa sedan en ny komponent för SignupForm.
ng generera komponent SignupForm
Ersätt innehållet i app.component.html med detta:
Här är katalogstrukturen för src / katalogen. Jag har tagit bort några icke-nödvändiga filer för att hålla sakerna enkla.
. ├── app │ ├── app.component.css │ ├── app.component.html │ ├── app.component.ts │ ├── app.module.ts │ ├── registreringsformulär │ │ ├ ─ - 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
Som du kan se, en katalog för SignupForm
komponenten har skapats automatiskt. Det är där de flesta av vår kod kommer att gå. Jag har också skapat en ny User.ts
för att lagra vår användarmodell.
Innan vi dyker in i själva komponentmallen behöver vi ha en abstrakt idé om vad vi bygger. Så här är den formstruktur som jag har i mitt sinne. Anmälningsformuläret kommer att ha flera inmatningsfält, ett väljelement och en kryssruta.
Här är HTML-mallen som vi ska använda för vår registreringssida.
CSS-klasserna som används i HTML-mallen är en del av Bootstrap-biblioteket som används för att göra saker ganska. Eftersom detta inte är en designtutorial, kommer jag inte att prata mycket om CSS-aspekterna av formuläret om det inte behövs.
För att kunna använda de malldrivna formulärdirektiven måste vi importera FormsModule
från @ kantiga / former
och lägg till den i import
array in app.module.ts
.
importera FormsModule från '@ vinkel / formulär'; @NgModule (... import: [BrowserModule, FormsModule], ...) exportklass AppModule
Skapa sedan en klass som håller alla egenskaper hos användar-enheten. Vi kan antingen använda ett gränssnitt och implementera det i komponenten eller använda en TypeScript-klass för modellen.
exportklass Användare id: nummer; email: string; // Båda lösenorden finns i ett enda objektlösenord: pwd: string; confirmPwd: string; ; kön: sträng; termer: booleska; konstruktör (värden: Objekt = ) // Konstruktorinitialisering Object.assign (detta, värden);
Skapa nu en förekomst av klassen i SignupForm-komponenten. Jag har också deklarerat en extra egenskap för könet.
importera Component, OnInit från '@ vinkel / kärna'; // Importera användarnamporten Användare från './.../User'; @Component (selector: 'app-signup-form', templateUrl: './signup-form.component.html', styleUrls: ['./signup-form.component.css']) exportklass SignupFormComponent implementerar OnInit // Egenskap för kön privat kön: sträng []; // Egenskap för användarens privata användare: Användare; ngOnInit () this.gender = ['Male', 'Female', 'Others']; // Skapa ett nytt användarobjekt this.user = new User (email: "), lösenord: pwd:" ", confirm_pwd:" ", kön: this.gender [0], termer: false);
För registrering-form.component.html fil, kommer jag att använda samma HTML-mall som diskuterats ovan, men med mindre ändringar. Anmälningsformuläret har ett väljfält med en lista med alternativ. Även om det fungerar, kommer vi att göra det på vinkeln genom att slingra igenom listan med hjälp av ngFor
direktiv.
Därefter vill vi binda formulärdata till användarklassobjektet så att när du anger registreringsdata i formuläret skapas ett nytt användarobjekt som tillfälligt lagrar den data. På så vis kan du hålla synvinkel synkroniserad med modellen, och detta kallas bindande.
Det finns ett par sätt att få detta att hända. Låt mig först presentera dig för ngModel
och ngForm
.
ngForm och ngModel är vinkeldirektiv som är nödvändiga för att skapa mallstyrda former. Låt oss börja med ngForm
först. Här är ett utdrag om ngForm från Angular docs.
DeNgForm
direktivet kompletterarform
element med ytterligare funktioner. Den innehåller kontrollerna du skapade för elementen med enngModel
direktiv ochnamn
attribut och övervakar deras egenskaper, inklusive deras giltighet. Det har också sin egengiltig
egendom som bara är sant om alla innehöll kontrollen är giltig.
Först uppdatera formuläret med ngForm
direktiv:
#signupForm
är en referensvariabel för mall som refererar till ngForm
direktiv som styr hela formuläret. Exemplet nedan visar användningen av a ngForm
referensobjekt för validering.
Här, signupForm.form.valid
kommer att returneras falskt om inte alla formulärelement överensstämmer med deras respektive valideringskontroller. Ingivningsknappen kommer att inaktiveras tills formuläret är giltigt.
När det gäller bindning av mallen och modellen finns det många sätt att göra detta, och ngModel
har tre olika syntaxer för att hantera denna situation. Dom är:
Låt oss börja med den första.
[(NgModel)]
utför dubbelriktad bindning för läsning och skrivning av inmatningskontrollvärden. Om en [(NgModel)]
direktivet används, matar inmatningsfältet ett initialvärde från den bundna komponentklassen och uppdaterar den tillbaka när någon ändring av ingångskontrollvärdet detekteras (vid tangenttryckning och knapptryckning). Bilden nedan beskriver den tvåvägsbindande processen bättre.
Här är koden för inmatningsfältet för e-post:
[(ngModel)] = "user.email"
binder användarens e-postegenskap till inmatningsvärdet. Jag har också lagt till en namn attribut och set name = "email"
. Detta är viktigt, och du kommer att få ett fel om du inte har deklarerat ett namnattribut medan du använder ngModel.
På samma sätt lägg till en [(NgModel)]
och en unik namn attribut till varje formelement. Din form ska se något så här nu:
......
De ngModelGroup
används för att gruppera liknande formulärfält så att vi kan köra valideringar endast i dessa formulärfält. Eftersom båda lösenordsfälten är relaterade lägger vi dem under en enda ngModelGroup. Om allt fungerar som förväntat, komponentbundet användare
egendom bör ansvara för att lagra alla formkontrollvärden. För att se detta i åtgärd, lägg till följande efter formtaggen:
user | json
Rör användaregenskapen genom JsonPipe
att göra modellen som JSON i webbläsaren. Det här är användbart för felsökning och loggning. Du bör se en JSON-utgång så här.
Värdena strömmar in från visningen till modellen. Vad sägs om tvärtom? Försök initiera användarobjektet med vissa värden.
this.user = ny användare (// initialiserad med viss data email: "[email protected]", lösenord: pwd: "", confirm_pwd: "", kön: this.gender [0]);
Och de visas automatiskt i vyn:
"email": "[email protected]", "lösenord": "pwd": "", "confirm_pwd": "", "gender": "Male"
Tvåvägsbindningen [(NgModel)]
syntax hjälper dig att bygga formulär utan problem. Det har emellertid vissa nackdelar; Därför finns det ett alternativt tillvägagångssätt som använder ngModel
eller [NgModel]
.
När ngModel
används, är vi faktiskt ansvariga för att uppdatera komponentegenskapen med inmatningskontrollvärdena och vice versa. Inmatningsdata flyter inte automatiskt till komponentens användaregenskap.
Så ersätt alla instanser av [(ngModel)] = ""
med ngModel
. Vi kommer att behålla namn
attribut eftersom alla tre versioner av ngModel behöver namn
attribut till arbetet.
Med ngModel
, värdet på namnattributet blir en nyckel i ngForm-referensobjektet signupForm
som vi skapade tidigare. Så, till exempel, signupForm.value.email
lagrar kontrollvärdet för e-post-id.
Byta ut user | json
med signupForm.value | json
för det är där all staten lagras just nu.
Vad händer om du behöver ställa in det ursprungliga tillståndet från den bundna klasskomponenten? Det är vad [NgModel]
gör för dig.
Här strömmar data från modellen till vyn. Gör följande ändringar i syntaxen för att använda envägsbindning:
Så vilken strategi ska du välja? Om du använder [(NgModel)]
och ngForm
tillsammans kommer du så småningom att ha två stater att behålla-användare
och signupForm.value
-och det kan vara potentiellt förvirrande.
"email": "[email protected]", "lösenord": "pwd": "thisispassword", "confirm_pwd": "thisispassword", "gender": "Male" //user.value " email ":" [email protected] "," lösenord ": " pwd ":" thisispassword "," confirm_pwd ":" thisispassword "," gender ":" Male " //signupForm.value
Därför rekommenderar jag att du använder den envägs bindande metoden istället. Men det är något för dig att bestämma.
Här är våra krav på validering.
Den första är lätt. Du måste lägga till en nödvändig
validering attribut till varje formulär element så här:
Förutom nödvändig
attribut, jag har också exporterat en ny #e-post
mallreferensvariabel. Det här är så att du kan komma åt inmatningsrutans kantlinjekontroll från mallen själv. Vi använder den för att visa fel och varningar. Använd nu knappens inaktiverade egenskap för att inaktivera knappen:
För att lägga till en begränsning på e-post, använd mönsterattributet som fungerar med inmatningsfält. Mönster används för att specificera reguljära uttryck som nedan:
mönster = "[a-z0-9 ._% + -]. + @ [a-z0-9 .-] + \ [a-z] 2,3 $"
För lösenordet är allt du behöver göra till att lägga till en minlength = ""
attribut:
För att visa felen kommer jag att använda det villkorliga direktivet ngIf
på ett div-element. Låt oss börja med ingångskontrollfältet för e-post:
E-postfältet kan inte vara tomtE-post-id verkar inte rätt
Det händer mycket här. Låt oss börja med den första raden i felsektionen.
Kom ihåg det
#e-post
variabel som vi exporterade tidigare? Den har viss information om ingångskontrolltillståndet i e-postfältet. Detta inkluderar:email.valid
,email.invalid
,email.dirty
,email.pristine
,email.touched
,email.untouched
, ochemail.errors
. Bilden nedan beskriver i detalj alla dessa egenskaper.Så div elementet med
* ngIf
kommer endast att göras om e-postmeddelandet är ogiltigt. Användaren kommer emellertid att hälsas med fel om inmatningsfälten är tomma även innan de har möjlighet att redigera formuläret.För att undvika detta scenario har vi lagt till det andra villkoret. Felet visas först efter kontrollen har besökts eller kontrollens värde har ändrats.
De kapslade div-elementen används för att täcka alla fall av valideringsfel. Vi använder
email.errors
för att kontrollera alla möjliga valideringsfel och sedan visa dem tillbaka till användaren i form av anpassade meddelanden. Följ nu samma procedur för övriga formulärelement. Så här har jag kodat validering för lösenord.app / registrerings-formen / registrering-form.component.html
Lösenordet måste vara mer än 8 teckenLösenorden matchar inte Detta börjar se lite rörigt ut. Angular har en begränsad uppsättning validatorattribut:
nödvändig
,minlength
,Maxlängd
, ochmönster
. För att täcka alla andra scenarier som lösenordsjämförelse måste du lita på kapsladengIf
conditionals som jag gjorde ovan. Eller helst skapar du en anpassad validatorfunktion som jag kommer att täcka i den tredje delen av denna serie.I koden ovan har jag använt
ngIf annat
syntax som introducerades i den senaste versionen av Angular. Så här fungerar det:Giltigt innehåll ...Ej giltigt innehåll ... Skicka formuläret med ngSubmit
Vi har nästan slutfört formuläret. Nu måste vi kunna lämna in formuläret och kontrollen av formulärdata ska överlämnas till en komponentmetod, säg
onFormSubmit ()
.app / registrerings-formen / signup-form.component.ts