Angular Template-Driven vs Reactive Forms
Below is a brief overview of the differences between Angular Reactive Forms and Template-Driven Forms followed by a simple example of each and how to choose between the two.
Angular Reactive Forms
Reactive forms use a model-driven approach where you define your form fields and validation rules in the component as a collection of controls in a FormGroup
, and bind it to the form element in the template with a data-binding attribute (e.g. <form ... [formGroup]="form">
).
To use Reactive Forms you need to import { ReactiveFormsModule } from '@angular/forms';
and add it to the imports
array of the @NgModule
decorator in your app module.
Angular Template-Driven Forms
With template-driven forms pretty much everything is defined in the template (as the name suggests). Form data is accessed via a template variable declared on the form element (e.g. <form #f="ngForm" ...>
), the ngModel
directive is used to register form input controls with the form (e.g. <input name="email" ngModel ... >
), directives are used to specify validation rules on input elements (e.g. <input ... required email>
), and model properties such as validation error messages (e.g. email.errors
) are accessed via template variables declared on input elements (e.g. <input ... #email="ngModel">
).
To use Template-Driven Forms you need to import { FormsModule } from '@angular/forms';
and add it to the imports
array of the @NgModule
decorator in your app module.
Reactive Forms Example
Below is a simple example form built with Reactive Forms, it contains a required field, a submit button and a reset button.
Angular Component with Reactive Forms
The app component contains an example form (FormGroup
) created with the formBuilder.group()
method, it contains a single form control for email
. The control has a required
validator and an email
validator, the email
validator tests that the control contains a valid email address.
The onSubmit()
method simply displays the form data in a javascript alert when the form is valid.
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({ selector: 'app-root', templateUrl: 'app.component.html' })
export class AppComponent implements OnInit {
form!: FormGroup;
submitted = false;
constructor(private formBuilder: FormBuilder) { }
ngOnInit() {
this.form = this.formBuilder.group({
email: ['', [Validators.required, Validators.email]]
});
}
// convenience getter for easy access to form fields
get f() { return this.form.controls; }
onSubmit() {
this.submitted = true;
// stop here if form is invalid
if (this.form.invalid) {
return;
}
// display form values on success
alert('SUCCESS!! :-)\n\n' + JSON.stringify(this.form.value, null, 4));
}
onReset() {
this.submitted = false;
this.form.reset();
}
}
Angular Component Template with Reactive Forms
The app component template contains the html markup for displaying the example email validation form in the browser. The form element uses the [formGroup]
directive to bind to the form
FormGroup in the app component above.
A specific validation message is displayed for each validator by checking the errors
object for the input field (*ngIf="f.email.errors.required"
and *ngIf="f.email.errors.email"
).
The form binds the form submit event to the onSubmit()
handler in the app component using the Angular event binding (ngSubmit)="onSubmit()"
. Validation messages are displayed only after the user attempts to submit the form for the first time, this is controlled with the submitted
property of the app component.
The reset button click event is bound to the onReset()
handler in the app component using the Angular event binding (click)="onReset()"
.
CSS classes are from Bootstrap 5.
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<div class="row">
<div class="col mb-3">
<label class="form-label">Email</label>
<input type="text" formControlName="email" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.email.errors }" />
<div *ngIf="submitted && f.email.errors" class="invalid-feedback">
<div *ngIf="f.email.errors.required">Email is required</div>
<div *ngIf="f.email.errors.email">Email must be a valid email address</div>
</div>
</div>
</div>
<div class="text-center">
<button class="btn btn-primary me-2">Submit</button>
<button class="btn btn-secondary" type="reset" (click)="onReset()">Reset</button>
</div>
</form>
See on StackBlitz at https://stackblitz.com/edit/angular-reactive-forms-email-validation
Template-Driven Forms Example
Below is a simple example form built with Template-Driven Forms, it contains a required field, a submit button and a reset button.
Angular Component with Template-Driven Forms
The component doesn't do much when using angular template-driven forms because form fields and validators are configured in the component template.
The onSubmit()
method is called with the NgForm
template variable when the form is submitted, it is bound to the form element in the template using Angular event binding syntax ((ngSubmit)="onSubmit(f)"
). If the form is valid a simple javascript alert
is displayed with the values entered.
import { Component } from '@angular/core';
import { NgForm } from '@angular/forms';
@Component({ selector: 'app-root', templateUrl: 'app.component.html' })
export class AppComponent {
onSubmit(f: NgForm) {
// stop here if form is invalid
if (f.invalid) {
return;
}
alert('SUCCESS!! :-)\n\n' + JSON.stringify(f.value, null, 4));
}
}
Angular Component Template with Template-Driven Forms
The app component template contains an example form with a single input field for email
. The field has the required
and email
validator directives, the email
validator tests that the input field contains a valid email address.
The form submit event is bound to the onSubmit()
method of the app component with the event binding (ngSubmit)="onSubmit(f)"
. The template variable #f="ngForm"
creates a FormGroup
instance to provide access to the form data and validation status in the app component.
Validators and directives in template-driven forms
Validation is implemented by validator functions that are attached to fields using directives in template-driven forms. The required
and email
validators are both included as part of the Angular framework.
Input fields registered with parent form
The email input field is registered with the form using the ngModel
directive. In the context of a parent form the directive can be used without data binding ([()]
), instead the control is registered using the input name
attribute and the form keeps the data in sync.
CSS classes are from Bootstrap 5.
<form #f="ngForm" (ngSubmit)="onSubmit(f)" novalidate>
<div class="row">
<div class="col mb-3">
<label class="form-label">Email</label>
<input type="text" name="email" ngModel #email="ngModel" class="form-control" [ngClass]="{ 'is-invalid': f.submitted && email.invalid }" required email>
<div *ngIf="f.submitted && email.errors" class="invalid-feedback">
<div *ngIf="email.errors.required">Email is required</div>
<div *ngIf="email.errors.email">Email must be a valid email address</div>
</div>
</div>
</div>
<div class="text-center">
<button class="btn btn-primary me-1">Submit</button>
<button class="btn btn-secondary" type="reset">Reset</button>
</div>
</form>
See on StackBlitz at https://stackblitz.com/edit/angular-template-driven-forms-email-validation
Which should I choose?
It's generally recommended to use Reactive Forms for anything other than simple scenarios because there's a cleaner separation of concerns between form logic and HTML markup. Testing is easier with the form defined in code, and it handles more complex scenarios better, for example a large form with a lot of validators is more readable when it's separated from the HTML.
That being said I think it always comes down to specific requirements and preferences. Template-Driven Forms are easy to use (especially if you're coming from AngularJS), require a minimal amount of component code and can do pretty much everyhting Reactive Forms can.
My opinion: choose the approach that satisfies all your project requirements and that you're most comfortable with (or like the most).
Details on the official Angular recommendation (Reactive Forms) are avaiable at https://angular.io/guide/forms-overview#choosing-an-approach.
Need Some Angular Help?
Search fiverr for freelance Angular developers.
Follow me for updates
When I'm not coding...
Me and Tina are on a motorcycle adventure around Australia.
Come along for the ride!