About
Angular infers the Form-Object (structure) from the DOM. (Better for more simple forms)
Some advantages include:
Have an asynchronous data-flow between View and Data model.
Data-flow is way more expensive, expecially in (Model-to-View) , when compared to Reactive-driven, since it needs to also call NgModel
methods.
(View-to-Model) and (Model-to-view). ( more info )
Rely on mutability of the Data Model with two-way binding to update the data model in the Component as changes are made in the Template.
Because there are no unique changes to track on the data model, change detection is less efficient at determining when updates are required.
Form validation is tied to template directives , and must provide custom validator directives that wrap validation functions.
Writing tests requires a detailed knowledge of the change detection process and an understanding of how directives run on each cycle to ensure that elements are queried, tested or change at the correct time. (more info )
Examples
Simple Setup - NgModel
without NgForm
Very simple and useless.
In template-driven NgModel
will automatically manage FormControl
for you, so you don't have to create it.
Copy @Component({
selector: "app-form-page",
imports: [FormsModule],
template: ` <input type="text" [(ngModel)]="username" /> `,
})
export class FormPageComponent {
username = "";
}
Regular Setup - NgModel
If there is no need to create class variables, handle form values ONLY inside the submit function.
Must provide name=""
attributes to the inputs.
Copy @Component({
selector: "app-form-page",
imports: [FormsModule],
template: `
<form #loginForm="ngForm" (ngSubmit)="handleSubmit(loginForm)">
<input type="text" name="username" ngModel />
<input type="password" name="password" ngModel />
</form>
`,
})
export class FormPageComponent {
protected handleSubmit(formData: NgForm) {
console.log(formData.form.value.username);
}
}
Regular Setup - Submiting with @ViewChild
Useful when you need to access the Form not only on submition.
Copy @Component({
selector: "app-form-page",
imports: [FormsModule],
template: `
<form #loginForm="ngForm" (ngSubmit)="handleSubmit()">
<input type="text" name="username" ngModel />
<input type="password" name="password" ngModel />
</form>
`,
})
export class FormPageComponent {
formData = viewChild<NgForm>("loginForm");
protected handleSubmit() {
this.formData();
}
}
Regular Setup - NgModel
two-way binding
With two-way binding for class variables.
Copy @Component({
selector: "app-form-page",
imports: [FormsModule],
template: `
<form #loginForm="ngForm" (ngSubmit)="handleSubmit(loginForm)">
<input type="text" [(ngModel)]="username" />
<input type="password" [(ngModel)]="password" />
</form>
`,
})
export class FormPageComponent {
username = "";
password = "";
protected handleSubmit(formData: NgForm) { ... }
}
Validation Setup
Only basic validation with the help of HTML5 validation.
Angular under the hood will wrap itself on these HTML validators like required
, email
, etc, and do additional stuff.
Just adding them will not prevent the form submition.
Copy @Component({
selector: "app-form-page",
imports: [FormsModule],
template: `
<form #loginForm="ngForm" (ngSubmit)="handleSubmit()">
<div>
<input type="text" name="username" ngModel required #email="ngModel" />
@if (!email.valid) {
<span>Invalid Username</span>
}
</div>
<div>
<input type="password" name="password" ngModel required minLength="6" />
</div>
</form>
`,
})
export class FormPageComponent {
handleSubmit(formData: NgForm) {
if (!formData.form.valid) return;
...
}
}