Using Angular FormBuilder to build Forms

Angular FormBuilder API makes it easier to build reactive forms. We can easily add the FormGroup, nested FormGroup’s, FormArray’s & FormControls easily. It also allows us to set up the Validation rules for each of the controls. In this tutorial, we will show you how to create a Form, add validation rules using the FormBuilder.

If you are new to Reactive Forms, we recommend you to learn how to build reactive forms.

What is FormBuilder

The FormBuilder is the helper API to build forms in Angular.  It provides shortcuts to create the instance of the FormControl, FormGroup or FormArray. It reduces the code required to write the complex forms.

How to use FormBuilder

Import & inject FormBuilder API

To use the FormBuilder, first, we need to import it in our component

import { FormBuilder } from '@angular/forms'

Next, we need to inject it into our component class

constructor(private formBuilder: FormBuilder) {
}

Finally, use the group, array & control methods to build the FormModel

FormGroup

We use the group method to build the Form Group. We pass the list of Form Controls, Form Array, or another Form Group to the group method as key-value pair. Where the key is the name of the FormControl, FormGroup or FormArray. The value is the configuration of the control.

In the following example, we have added six form controls. The First argument to the FormControl is the initial value, which we set to empty string.

this.contactForm = this.formBuilder.group({
  firstname: [''],
  lastname: [''],
  email: [''],
  gender: [''],
  isMarried: [''],
  country: [''],
});

Nested FormGroup

Creating a Nested FormGroup is just as easy. use the formbuilder.group method, as shown below.

this.contactForm = this.formBuilder.group({
  firstname: [''],
  lastname: [''],
  email: [''],
  gender: [''],
  isMarried: [''],
  country: [''],
  address: this.formBuilder.group({
    city: [''],
    street: [''],
    pincode: ['']
  })
})

Validations

The second argument to the FormControl is the list of sync validators. The following example shows how to add validators.

this.contactForm = this.formBuilder.group({
  firstname: ['', [Validators.required, Validators.minLength(10)]],
  lastname: ['', [Validators.required, Validators.maxLength(15), Validators.pattern("^[a-zA-Z]+$")]],
  email: ['', [Validators.required, Validators.email]],
  gender: ['', [Validators.required]],
  isMarried: ['', [Validators.required]],
  country: ['', [Validators.required]],
  address: this.formBuilder.group({
    city: ['', [Validators.required]],
    street: ['', [Validators.required]],
    pincode: ['', [Validators.required]],
  })
});

FormBuilder Example

We learned how to build reactive forms the Angular Reactive forms tutorial.

app.component.ts

import { Component, ViewChild, ElementRef } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms'
import { FormBuilder } from '@angular/forms'
import { groupBy } from 'rxjs/internal/operators/groupBy';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  title = 'Angular Reactive forms';

  contactForm;

  constructor(private formBuilder: FormBuilder) {



    // this.contactForm = this.formBuilder.group({
    //   firstname: [''],
    //   lastname: [''],
    //   email: [''],
    //   gender: [''],
    //   isMarried: [''],
    //   country: [''],
    // });

    // this.contactForm = this.formBuilder.group({
    //   firstname: [''],
    //   lastname: [''],
    //   email: [''],
    //   gender: [''],
    //   isMarried: [''],
    //   country: [''],
    //   address: this.formBuilder.group({
    //     city: [''],
    //     street: [''],
    //     pincode: ['']
    //   })
    // });

    this.contactForm = this.formBuilder.group({
      firstname: ['', [Validators.required, Validators.minLength(10)]],
      lastname: ['', [Validators.required, Validators.maxLength(15), Validators.pattern("^[a-zA-Z]+$")]],
      email: ['', [Validators.required, Validators.email]],
      gender: ['', [Validators.required]],
      isMarried: ['', [Validators.required]],
      country: ['', [Validators.required]],
      address: this.formBuilder.group({
        city: ['', [Validators.required]],
        street: ['', [Validators.required]],
        pincode: ['', [Validators.required]],
      })
    });
  }


  get firstname() {
    return this.contactForm.get('firstname');
  }

  get lastname() {
    return this.contactForm.get('lastname');
  }

  get email() {
    return this.contactForm.get('email');
  }

  get gender() {
    return this.contactForm.get('gender');
  }

  get isMarried() {
    return this.contactForm.get('isMarried');
  }

  get country() {
    return this.contactForm.get('country');
  }

  get city() {
    return this.contactForm.get("address").get('city');
  }

  get street() {
    return this.contactForm.get("address").get('street');
  }

  get pincode() {
    return this.contactForm.get("address").get('pincode');
  }


  countryList: country[] = [
    new country("1", "India"),
    new country('2', 'USA'),
    new country('3', 'England')
  ];

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

}


export class country {
  id: string;
  name: string;

  constructor(id: string, name: string) {
    this.id = id;
    this.name = name;
  }
}

app.component.html

<div style="float: left; width:50%;">

<form [formGroup]="contactForm" (ngSubmit)="onSubmit()" novalidate>

  <p>
    <label for="firstname">First Name </label>
    <input type="text" id="firstname" name="firstname" formControlName="firstname">
  </p>

  <div
    *ngIf="!firstname?.valid && (firstname?.dirty ||firstname?.touched)">
    <div [hidden]="!firstname.errors.required">
      First Name is required
    </div>
    <div [hidden]="!firstname.errors.minlength">
      Min Length is 10
    </div>
  </div>

  <p>
    <label for="lastname">Last Name </label>
    <input type="text" id="lastname" name="lastname" formControlName="lastname">
  </p>

  <div *ngIf="!lastname.valid && (lastname.dirty ||lastname.touched)">
    <div [hidden]="!lastname.errors.pattern">
      Only characters are allowed
    </div>
    <div [hidden]="!lastname.errors.maxLength">
      Max length allowed is {{lastname.errors.maxlength?.requiredLength}} 
    </div>
    <div [hidden]="!lastname.errors.required">
      Last Name is required
    </div>
  </div>

  <p>
    <label for="email">Email </label>
    <input type="text" id="email" name="email" formControlName="email">
  </p>
  <div *ngIf="!email.valid && (email.dirty ||email.touched)">
    <div [hidden]="!email.errors.required">
      email is required
    </div>
    <div [hidden]="!email.errors.email">
      invalid email id
    </div>
  </div>


  <p>
    <label for="gender">Geneder </label>
    <input type="radio" value="male" id="gender" name="gender" formControlName="gender"> Male
    <input type="radio" value="female" id="gender" name="gender" formControlName="gender"> Female
  </p>
  <div *ngIf="!gender.valid && (gender.dirty ||gender.touched)">
    <div [hidden]="!gender.errors.required">
      gender is required
    </div>
  </div>

  <p>
    <label for="isMarried">Married </label>
    <input type="checkbox" id="isMarried" name="isMarried" formControlName="isMarried">
  </p>
  <div *ngIf="!isMarried.valid && (isMarried.dirty ||isMarried.touched)">
    <div [hidden]="!isMarried.errors.required">
      isMarried is required
    </div>
  </div>


  <p>
    <label for="country">country </label>
    <select id="country" name="country" formControlName="country">
      <option [ngValue]="c.id" *ngFor="let c of countryList">
        {{c.name}}
      </option>
    </select>
  </p>
  <div *ngIf="!country.valid && (country.dirty ||country.touched)">
    <div [hidden]="!country.errors.required">
      country is required
    </div>
  </div>

  <div formGroupName="address">

    <div class="form-group">
      <label for="city">City</label>
      <input type="text" class="form-control" name="city" formControlName="city">
    </div>
    <div *ngIf="!city.valid && (city.dirty ||city.touched)">
      <div [hidden]="!city.errors.required">
        city is required
      </div>
    </div>


    <div class="form-group">
      <label for="street">Street</label>
      <input type="text" class="form-control" name="street" formControlName="street">
    </div>
    <div *ngIf="!street.valid && (street.dirty ||street.touched)">
      <div [hidden]="!street.errors.required">
        street is required
      </div>
    </div>

    <div class="form-group">
      <label for="pincode">Pin Code</label>
      <input type="text" class="form-control" name="pincode" formControlName="pincode">
    </div>
    <div *ngIf="!pincode.valid && (pincode.dirty ||pincode.touched)">
      <div [hidden]="!pincode.errors.required">
        pincode is required
      </div>
    </div>

  </div> 

  <p>
    <button type="submit" [disabled]="!contactForm.valid">Submit</button>
  </p>

</form>

</div>

<div style="float: right; width:50%;">

  <h3>Form Status</h3>
  <b>valid : </b>{{contactForm.valid}}
  <b>invalid : </b>{{contactForm.invalid}}
  <b>touched : </b>{{contactForm.touched}}
  <b>untouched : </b>{{contactForm.untouched}}
  <b>pristine : </b>{{contactForm.pristine}}
  <b>dirty : </b>{{contactForm.dirty}}
  <b>disabled : </b>{{contactForm.disabled}}
  <b>enabled : </b>{{contactForm.enabled}}

  <h3>Form Value</h3>
  {{contactForm.value |json}}

</div>

References

  1. FormBuilder API

Summary

FormBuilder API makes it easier to work with the reactive forms in Angular. We can make use of the group, array & control methods to build ourFormModel. FormBuilder reduces the code required to write the complex forms.

  1. Angular Forms Tutorial: Fundamental & Concepts
  2. Template Driven Forms in Angular
  3. Set Value in Template Driven forms in Angular
  4. Reactive Forms in Angular
  5. FormBuilder in Reactive Forms
  6. SetValue & PatchValue in Angular
  7. StatusChanges in Angular Forms
  8. ValueChanges in Angular Forms
  9. FormControl
  10. FormGroup
  11. FormArray Example
  12. Build Dynamic or Nested Forms using FormArray
  13. Validations in Reactive Forms in Angular
  14. Custom Validator in Reactive Forms
  15. Passing Parameter to Custom Validator in Reactive Forms
  16. Inject Service into Custom Validator
  17. Validation in Template Driven Forms
  18. Custom Validator in Template Driven Forms

6 thoughts on “Using Angular FormBuilder to build Forms”

  1. I understand, FormBuilder and Reactive forms make testing and control over inputs easier, but still the code looks way smaller and efficient while using template driven forms. Also if working with many input fields, Reactive Forms does not follow the “Separation of Concerns” Principle because component is controlling the entire template. Other than Unit Testing and Better control, Is there any more advantage of using Reactive forms over template driven forms ?

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top