Template-driven forms.
Wat is een template-driven form?
In een template-driven form zit de volledige logica en validatie in de template (de HTML-pagina) ingebouwd.
De twee directives, ngForm op de form-tag en ngModel op de formulierelementen, bepalen welke data er uiteindelijk wordt doorgestuurd.
Voor client-side validatie gebruik je de standaard type-attributen (email, phone, ...) en de validatie-attributen van de elementen (required, minlength, pattern, ...).
Zie ook : Angular
Forms
Tutorial (1 - 14)
Template-driven form.
Bestudeer de code van https://stackblitz.com/edit/tmk-templateform1
Deze pagina bevat een standaard formulier met twee input-velden en een submit-button. Merk op dat de action op de form-tag ontbreekt. Deze heb je niet nodig binnen Angular.
Een Template-driven form bestaat uit:
- Een form-tag met een template-variabele, gekoppeld aan de ngForm-directive #contactForm="ngForm".
Je kan de form nu uitlezen met contactForm.value. - Stuur de gegevens via het submit-event op de form-tag door naar het achterliggend script
(submit)="addUser(contactForm.value)".
In ons voorbeeld worden de gegevens enkel in de console getoond. - Elk veld dat je wil uitlezen MOET een name-attribuut hebben (bv: name="email").
- Elk veld dat je wil uitlezen MOET een ngModel-directive hebben.
- Zonder data-binding:
<input ... ngModel> - Met data-binding:
<input ... #myName="ngModel" [(ngModel)]="user.name">
- Zonder data-binding:
- Met data-binding kies je voor het name-attribuut en de template-variabele meestal dezelfde naam, maar dit is niet verplicht.
Merk op dat beide velden reeds HTML5-validatie hebben (required, minlength en pattern), maar dat de controle blijkbaar niet werkt. Angular neemt namelijk de volledige validatie van de browser over. In de achtergrond wordt er wel degelijk gecontroleerd, maar voorlopig gebeurt daar niets mee. Je kan het formulier voorlopig perfect verzenden met twee lege tekstvelden.
De button heeft geen name-attribuut en geen ngModel-directive. Dit heeft ook weinig zin omdat de button toch geen nuttige informatie bevat.
PS: de email-validatie gebeurt via een zeer eenvoudig regex-patroon. In een echte toepassing kan je
het patroon veel strikter en nauwkeuriger maken, maar voor dit voorbeeld is dit zeker voldoende.
Wat dit patroon juist betekent, kan je op regexr.com achterhalen.
Globale form-validatie.
Bestudeer de code van https://stackblitz.com/edit/tmk-templateform2
Mits een kleine toevoeging kan je het formulier globaal valideren en afhankelijk van de toestand de submit-button al dan niet aanklikbaar maken.
De template-variabele contactForm heeft naast de value-eigenschap nog twee interessante eigenschappen die voor onze toepassing belangrijk zijn.
- contactForm.valid:
is true indien het formulier volledig valide is. - contactForm.invalid:
is true indien het formulier niet volledig valide is.
Je kan dus één van beide eigenschappen gebruiken om de submit-button actief/inactief te zetten.
Zolang de validatie niet correct is, krijgt de submit-button, via event-binding, het attribuut
disabled.
Beide opties zijn dus mogelijk:
- [disabled]="contactForm.invalid"
- [disabled]="!contactForm.valid"
Individuele input-validatie (visuele indicatie).
Bestudeer de code van https://stackblitz.com/edit/tmk-templateform3
Naast een globale validatie is het natuurlijk ook belangrijk dat je de gebruiker over de toestand van elke input informeert. Het veld is niet ingevuld, het veld voldoet niet aan het vooropgestelde patroon, niet voldoende karakters ingevuld, enz...
ngModel op de formulier-elementen geeft je meer dan alleen maar two-way binding. Het geeft ook
aan of de gebruiker het veld heeft aangeraakt, of de waarde is gewijzigd of dat de waarde
geldig/ongeldig is. Kijk maar eens in de broncode wat er gebeurt indien je een veld wijzigt. Je zal
merken dat er steeds 3 extra klassen aan het veld worden toegevoegd.
(De form-tag heeft trouwens net dezelfde klassen.)
| Toestand | Klasse indien waar | Klasse indien niet waar |
|---|---|---|
| Input is gewijzigd | ng-dirty | ng-pristine |
| Input is aangeraakt | ng-touched | ng-untouched |
| Input is geldig | ng-valid | ng-invalid |
Je kan deze klassen bijvoorbeeld gebruiken om het uiterlijk van het veld via eigen CSS-code vorm te geven. Bijvoorbeeld: input.ng-invalid.ng-touched {color: red}. In onze oefening kiezen we voor een andere oplossing.
Bootstrap bevat reeds eigen klassen om de rand van een veld te kleuren.
- Een veld met class="... is-valid" krijgt een groene rand.
- Een veld met class="... is-invalid" krijgt een rode rand.
Net zoals de form-tag, heeft ook elk veld zes eigenschappen met dezelfde naam als de klassen, maar dan zonder het ng-voorvoegsel.
| Toestand | Indien waar | Indien niet waar |
|---|---|---|
| Input is gewijzigd | myName.dirty | myName.pristine |
| Input is aangeraakt | myMame.touched | myMame.untouched |
| Input is geldig | myMame.valid | myMame.invalid |
Bovenstaande eigenschappen kan je zelf combineren om aan te geven hoe en wanneer de klasse is-valid en is-invalid worden toegekend. In ons voorbeeld is dit:
- [class.is-valid]="myName.touched && myName.valid"
Groene rand indien het veld is aangeraakt EN de waarde is geldig. - [class.is-invalid]="myName.touched && myName.invalid"
Rode rand indien het veld is aangeraakt EN de waarde is ongeldig.
Individuele input-validatie (tekstuele indicatie).
Bestudeer de code van https://stackblitz.com/edit/tmk-templateform4
Naast een visuele indicatie kan je best ook met een korte omschrijving aangeven wat er mis is. Je gebruikt dan dezelfde eigenschappen om al dan niet een omschrijving te tonen.
Ook hier bepaal je weer zelf wanneer welke foutboodschap verschijnt. In ons voorbeeld zijn alle mogelijke foutboodschappen omsloten door een div-tag. De div-tag wordt via *ngIf enkel getoond indien de waarde niet geldig is en indien het veld nog niet is aangeraakt of niet werd gewijzigd.
Binnen de div-tag heb je weer twee mogelijkheden om een tekst te tonen/verbergen. Ofwel verberg je een foutomschrijving met *ngIf="..." (zie myName), ofwel verberg je een foutomschrijving met [hidden]="..." (zie myEmail).