Telerik blogs

One of two types of built-in form validation from Angular, reactive forms allow us to create form objects and link them to forms, which lets us add validation.

Angular has form validation built in as a feature. This lets us add forms with validation easily. It comes with two types of forms. One is template-driven forms and the other is reactive forms.

Template-driven forms let us add directives to bind input values to reactive values and also to add form validation.

Reactive forms work by letting us create form objects and link them to forms, which lets us add validation. It binds input values to properties in reactive form objects so we can access input values and validate them.

In this article, we will look at what reactive forms are and how to use them.

What are Reactive Forms?

Reactive forms objects are objects that provide us with synchronous access to form value data. They’re built from observables, so input values and the data value that they bind to are synchronous. Each change in a form state returns a new state.

This is different from template-driven forms since changes are asynchronous in template-driven forms.

The synchronous nature of reactive forms makes testing reactive forms easier than template-driven forms.

When Do We Use Reactive Forms?

Reactive forms should be used in most Angular apps.

The only benefit that template-driven forms have over reactive forms is that the syntax of template-driven forms is closer to Angular.js forms. Therefore, using template-driven forms would make migrating from Angular.js apps to Angular easier.

Other than that, there isn’t much benefit to using template-driven forms in our Angular apps. So unless we are migrating Angular.js apps to Angular, we should stick with reactive forms.

The immutability and the predictability because of the synchronous updates of reactive forms makes development much easier. In addition, reactive forms let us define the form’s structure explicitly so it’s easy to understand and better for scalability.

Reactive Forms Usage

To discover the usefulness of reactive forms, we will create one.

We start by importing the ReactiveFormsModule by writing:

app.module.ts

import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { ReactiveFormsModule } from "@angular/forms";

import { AppComponent } from "./app.component";

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, ReactiveFormsModule],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

We import ReactiveFormsModule into our Angular module so we can create reactive forms in the components in AppModule.

Then we create a form group object in a component by writing:

app.component.ts

import { Component } from "@angular/core";
import { FormGroup, FormControl } from "@angular/forms";
import { Validators } from "@angular/forms";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  signUpForm = new FormGroup({
    firstName: new FormControl("", [
      Validators.required,
      Validators.minLength(5)
    ]),
    lastName: new FormControl("", [
      Validators.required,
      Validators.minLength(5)
    ]),
    address: new FormGroup({
      street: new FormControl("", [
        Validators.required,
        Validators.minLength(5)
      ]),
      city: new FormControl("", [Validators.required, Validators.minLength(5)]),
      region: new FormControl("", [Validators.required])
    })
  });

  updateProfile() {
    this.signUpForm.patchValue({
      firstName: "Jane",
      lastName: "Smith",
      address: {
        street: "123 1st Street"
      }
    });
  }

  onSubmit() {
    console.log(this.signUpForm.value);
  }
}

We added a FormGroup object into our AppComponent. We created it by adding fields into the object we passed into FormGroup.

The object has the field names as property keys, which we will use to associate with input fields so we can bind input values to component values and provide validation for each field.

The values are FormControl objects. We pass in the initial value and an array of validators into FormControl respectively.

Angular provides a variety of form field validators in the Validators object. We make a form field required with Validators.required and enforce a minimum length of input values with Validators.minLength.

We can manipulate forms in the component’s code. In the updateProfile method, we call this.signUpForm.patchValue to update the input value of the firstName, lastName and address.street fields. And we get the input values of all the fields by using the this.signUpForm.value property.

Next, in our template, we add our form HTML code. In app.component.html, we write:

<form [formGroup]="signUpForm" (ngSubmit)="onSubmit()">
  <label for="first-name">First Name: </label>
  <input id="first-name" type="text" formControlName="firstName" />

  <div
    *ngIf="signUpForm.controls.firstName.invalid && (signUpForm.controls.firstName.dirty || signUpForm.controls.firstName.touched)"
  >
    <div *ngIf="signUpForm.controls.firstName.errors?.required">
      First name is required.
    </div>
    <div *ngIf="signUpForm.controls.firstName.errors?.minlength">
      First name must be at least 5 characters long.
    </div>
  </div>
  <br />

  <label for="last-name">Last Name: </label>
  <input id="last-name" type="text" formControlName="lastName" />

  <div
    *ngIf="signUpForm.controls.lastName.invalid && (signUpForm.controls.firstName.dirty || signUpForm.controls.lastName.touched)"
  >
    <div *ngIf="signUpForm.controls.lastName.errors?.required">
      Last name is required.
    </div>
    <div *ngIf="signUpForm.controls.lastName.errors?.minlength">
      Last name must be at least 5 characters long.
    </div>
  </div>
  <br />

  <div formGroupName="address">
    <h2>Address</h2>

    <label for="street">Street: </label>
    <input id="street" type="text" formControlName="street" />
    <br />

    <div
      *ngIf="signUpForm.controls.address.controls.street.invalid && (signUpForm.controls.address.controls.street.dirty || signUpForm.controls.address.controls.street.touched)"
    >
      <div *ngIf="signUpForm.controls.address.controls.street.errors?.required">
        Last name is required.
      </div>
      <div
        *ngIf="signUpForm.controls.address.controls.street.errors?.minlength"
      >
        Last name must be at least 5 characters long.
      </div>
    </div>

    <label for="city">City: </label>
    <input id="city" type="text" formControlName="city" />
    <br />

    <label for="region">Region: </label>
    <input id="region" type="text" formControlName="region" />
    <br />

    <button type="button" (click)="updateProfile()">Update Profile</button>
    <button type="submit" [disabled]="!signUpForm.valid">Submit Profile</button>
  </div>
</form>

To associate the form group object to an HTML form, we set the [formGroup] attribute to the name of the FormGroup instance we defined in our component.

We set (ngSubmit) to onSubmit() to call onSubmit when we submit the form.

And we set the formControlName attribute to the name of the FormControl instance to associate the form control object to the form field. This will bind the input value to the form control object’s value and also lets us add validation by checking properties in the form control object.

To get the validation states from form control objects, we use the signUpForm.controls property. We use signUpForm.controls.firstName to get the validation state of the firstName form control. And we do the same with lastName.

We get the validation errors from the firstName form control with signUpForm.controls.firstName.errors.

To check whether the whole form is valid, we use the signUpForm.valid property.

To associate a group of fields to a form group, we set the formGroupName attribute as we did with the div to associate the fields in the form group to the address form group.

To get the validation state of nested fields, we keep using the controls property.

We get the street field with signUpForm.controls.address.controls.street. And the validation states are in that object.

With reactive forms, we can bind input values to component property values and add validation easily by creating a single object. Also, we can update input values with that object with patchValue. And we associate HTML input fields with the form control objects with a few attributes.

All these operations are synchronous, so the workflow is predictable.

Validators are explicitly added to form controls so we can read and change validation of each field easily. And Angular provides many validators for reactive forms so we can use many of them instead of writing our own validation logic. Nested form fields are also easy to add since we can nest form groups.

Therefore, there is not much of a use case for using template-driven forms or creating our own form validation solutions.

Reactive forms come standard with Angular so we do not have to install anything to use it.

Conclusion

Angular has form validation built in as a feature. This lets us add forms with validation easily. It comes with two types of forms—reactive and template-driven forms.

Template-driven forms let us add directives to bind input values to reactive values and also to add form validation.

Reactive forms work by letting us create form objects and link them to forms, which lets us add validation. It binds input values to properties in reactive form objects so we can access input values and validate them. It also lets us add form validation in an explicit manner and we can use the provided validators to add validations to fields.

From groups let us organize forms fields into groups and we can nest form groups easily. We can also get and set form values easily in a synchronous manner with reactive forms.

Therefore, reactive forms are better than template-driven forms or creating our own form field binding and validation solutions in almost all cases.


About the Author

John Au-Yeung

John Au-Yeung is a frontend developer with 6+ years of experience. He is an avid blogger (visit his site at https://thewebdev.info/) and the author of Vue.js 3 By Example.

Related Posts

Comments

Comments are disabled in preview mode.