ngModel & a Few Directives — That's the Form
Template-Driven Forms
Bind inputs with two-way ngModel and let Angular construct the FormControl tree implicitly from your template.
What you'll learn
- Import FormsModule
- Bind inputs with ngModel and name
- Access the form via a template reference
Template-driven forms keep the form definition in the template. Angular reads it and builds an internal FormGroup for you.
Setup
You need FormsModule in the component’s imports.
import { Component } from '@angular/core';
import { FormsModule, NgForm } from '@angular/forms';
@Component({
selector: 'app-signup',
standalone: true,
imports: [FormsModule],
template: `
<form #f="ngForm" (ngSubmit)="save(f)">
<label>
Email
<input name="email" [(ngModel)]="email" required email />
</label>
<label>
Password
<input name="password" type="password" [(ngModel)]="password"
required minlength="8" />
</label>
<button [disabled]="f.invalid">Sign up</button>
</form>
`,
})
export class SignupComponent {
email = '';
password = '';
save(form: NgForm) {
console.log(form.value);
}
} Three things make this work:
[(ngModel)]two-way binds the input to the class propertyname="email"registers it inside the form#f="ngForm"gives you a reference to the form for submit handling
Reading Field State
Each ngModel exposes its own control. You can pull it out with a template variable.
<input name="email" [(ngModel)]="email" required email #emailRef="ngModel" />
@if (emailRef.invalid && emailRef.touched) {
<p class="err">Enter a valid email.</p>
} emailRef.errors, .dirty, .touched, .valid are all available. Validators are HTML attributes — required, minlength, maxlength, pattern, email.
Submitting
(ngSubmit) fires on form submit and gives you the NgForm. form.value is the object of field values; form.valid is the overall validity.