José Matos
•23 Mar 2023
As an Angular developer, forms are one of the key components you’ll work with when building applications. While template-driven forms are simple and easy to understand, reactive forms are more dynamic and efficient.
In this article, we’ll explore reactive forms in Angular and the benefits they bring to your development process. We’ll go over how to create reactive forms, how to bind and validate form data, and how to use them in real-world scenarios.
Reactive forms are a type of form in Angular that uses reactive programming principles. Instead of being tightly coupled to the template and relying on events and two-way data binding, reactive forms use an observable pattern to manage form states and changes.
With reactive forms, you create your form model in TypeScript code as an instance of FormGroup
or FormArray
. FormGroup represents a collection of form controls, while FormArray represents an array of form controls that can dynamically change based on user input.
Reactive forms provide a way to sync your form data with the model, in a way that’s more predictable and efficient than template-driven forms.
To create a reactive form, you’ll need to import ReactiveFormsModule
from @angular/forms
in your module file. Then, in your component, you’ll need to create an instance of FormGroup
and define its form controls:
import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'app-my-form',
templateUrl: './my-form.component.html',
styleUrls: ['./my-form.component.css']
})
export class MyFormComponent {
myForm: FormGroup;
constructor(private fb: FormBuilder) {
this.createForm();
}
createForm() {
this.myForm = this.fb.group({
firstName: '',
lastName: '',
email: ''
});
}
}
In the above example, we’re creating a reactive form called myForm
, which contains three form controls: firstName, lastName, and email. We’re using the FormBuilder
service to define the form controls, which provides a simpler and more readable way to build reactive forms.
Once you have your reactive form set up, you can bind form data to your template and validate user input using built-in Angular directives.
To bind form data to your template, you’ll use the formGroup
directive and the formControlName
directive like this:
<form [formGroup]="myForm">
<label for="firstName">First Name:</label>
<input type="text" formControlName="firstName">
<label for="lastName">Last Name:</label>
<input type="text" formControlName="lastName">
<label for="email">Email:</label>
<input type="text" formControlName="email">
</form>
With the above code, we’re binding our reactive form myForm
to our template using the formGroup
directive. We’re also using the formControlName
directive to bind each form control to its corresponding input field.
With reactive forms, you can also validate user input using built-in Angular validators or by creating your custom validators.
Angular has several built-in validators, including required, email, minLength, and maxLength. To use these validators, you’ll need to add them to your form controls like this:
this.myForm = this.fb.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
email: ['', [Validators.required, Validators.email]]
});
In the above example, we’re using the Validators
class to add required and email validators to our email form control.
You can also create custom validators by creating a function that returns a validator function. Here’s an example:
function forbiddenNameValidator(forbiddenName: string) {
return (control: AbstractControl) => {
const forbidden = control.value === forbiddenName;
return forbidden ? { 'forbiddenName': { value: control.value } } : null;
};
}
this.myForm = this.fb.group({
firstName: ['', [Validators.required, forbiddenNameValidator('admin')]],
lastName: ['', Validators.required],
email: ['', [Validators.required, Validators.email]]
});
In the above example, we’re creating a custom validator called forbiddenNameValidator
that checks if the form control value is equal to admin
. If it is, the validator returns an error object that can be used to display an error message to the user.
Reactive forms are powerful and flexible enough to handle complex form scenarios, such as forms with dynamic fields or forms that require custom validation logic.
For example, let’s say you’re building a flight booking application and need to create a reactive form that handles multiple passengers with varying flight preferences.
You can use a FormArray
to dynamically add and remove form controls for each passenger, like this:
createPassengerForm() {
return this.fb.group({
firstName: '',
lastName: '',
preferences: this.fb.group({
mealType: '',
seatType: ''
})
});
}
this.myForm = this.fb.group({
flightNumber: ['', Validators.required],
passengers: this.fb.array([this.createPassengerForm()])
});
In the above example, we’re creating a reactive form that has a FormArray
called passengers
. Each passenger is represented by a dynamically created instance of createPassengerForm()
.
With dynamic forms like this, you can add and remove passengers as needed using built-in Angular directives like formArrayName
, formGroupName
, and formArray
.
Reactive forms in Angular are a powerful and efficient way to handle forms in your applications. By using observable patterns and a reactive programming approach, reactive forms bring greater flexibility, predictability, and performance to your forms.
In this article, we’ve covered how to create reactive forms, bind and validate form data, and use reactive forms in real-world scenarios. By mastering reactive forms in Angular, you’ll be able to build complex and dynamic forms that meet the needs of your users.