typescript 73 lines · 9 steps

How template-driven forms validate in Angular

An Angular signup form binds fields with ngModel and drives validation and submission from template references.

Explained by highlit
1import { Component } from '@angular/core';
2import { NgForm } from '@angular/forms';
3 
4interface SignupModel {
5 fullName: string;
6 email: string;
7 age: number | null;
8}
9 
10@Component({
11 selector: 'app-signup-form',
12 template: `
13 <form #signupForm="ngForm" (ngSubmit)="onSubmit(signupForm)" novalidate>
14 <label>
15 Full name
16 <input
17 name="fullName"
18 [(ngModel)]="model.fullName"
19 #fullName="ngModel"
20 required
21 minlength="3" />
22 </label>
23 <div class="error" *ngIf="fullName.invalid && (fullName.dirty || fullName.touched)">
24 <small *ngIf="fullName.errors?.['required']">Name is required.</small>
25 <small *ngIf="fullName.errors?.['minlength']">At least 3 characters.</small>
26 </div>
27 
28 <label>
29 Email
30 <input
31 name="email"
32 type="email"
33 [(ngModel)]="model.email"
34 #email="ngModel"
35 required
36 email />
37 </label>
38 <div class="error" *ngIf="email.invalid && email.touched">
39 <small *ngIf="email.errors?.['required']">Email is required.</small>
40 <small *ngIf="email.errors?.['email']">Enter a valid email address.</small>
41 </div>
42 
43 <label>
44 Age
45 <input
46 name="age"
47 type="number"
48 [(ngModel)]="model.age"
49 #age="ngModel"
50 required
51 min="18" />
52 </label>
53 <div class="error" *ngIf="age.invalid && age.touched">
54 <small *ngIf="age.errors?.['required']">Age is required.</small>
55 <small *ngIf="age.errors?.['min']">You must be at least 18.</small>
56 </div>
57 
58 <button type="submit" [disabled]="signupForm.invalid">Create account</button>
59 </form>
60 `,
61})
62export class SignupFormComponent {
63 model: SignupModel = { fullName: '', email: '', age: null };
64 
65 onSubmit(form: NgForm): void {
66 if (form.invalid) {
67 form.control.markAllAsTouched();
68 return;
69 }
70 console.log('Submitting', this.model);
71 form.resetForm();
72 }
73}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Template-driven forms let the template own validation state via exported ngModel and ngForm references.
  2. 2Two-way ngModel binding keeps a typed model object in sync with the inputs automatically.
  3. 3Guarding error messages behind dirty or touched prevents warnings from flashing before the user interacts.

Related explainers

Share this explainer

Here's the card — post it anywhere.

How template-driven forms validate in Angular — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code