Angular: Create Dynamic Forms Using FormArray

Angular: Create Dynamic Forms Using FormArray

In this article we are going to cover step by step guide to create dynamic form in angular.

Here we are going with an example where a user is signing up for a service and he has the option to provide multiple roles. In this article, you’ll learn to create a dynamic form in Angular and also hear a high-level explanation of other useful classes of Angular reactive forms

Reactive Forms

Angular provides two types of forms.

  • Template-driven forms

  • Reactive forms

Setting up the Project

To work with reactive forms, you need to add ReactiveFormsModule in the imports array of the AppModule.

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

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

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

Now, add the HTML markup with the form using the [FormGroup] directive. Don't worry we will cover the explanation later in this article.

<form [formGroup]="form">
  <div class="input-field">
    <input matInput type="email" name="email" placeholder="Email" formControlName="email">
  </div>
  <div class="input-field">
    <input matInput type="password" placeholder="Password" formControlName="password">
  </div>
  <div *ngFor="let control of  rolesFieldAsFormArray.controls; let i = index;" formArrayName='roles'>
    <div [formGroupName]="i">
      <div class="input-field">
        <input matInput type="text" placeholder="Role" formControlName="role">
      </div>
      <button class="button" type="button" (click)="remove(i)">Remove</button>
    </div>
  </div>
  <button class="button" (click)="addControl()"> Add New Role</button>
  <button class="button" type="submit" (click)="submit()">
    Login
  </button>
</form>

We have markup in place. Notice, formArrayName='roles' directive is very important without which no control will show up. now it's your turn to add functions and methods in the component's class.

import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators, FormArray } from '@angular/forms';

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

  constructor(private fb: FormBuilder) {
    this.form = this.fb.group({
      email: [
        '',
        {
          validators: [Validators.required, Validators.email],
        },
      ],
      password: ['', [Validators.required, Validators.minLength(8)]],
      roles: this.fb.array([]),
    });

  }

  get rolesFieldAsFormArray(): any {
    return this.form.get('roles') as FormArray;
  }

  role(): any {
    return this.fb.group({
      role: ['', Validators.required]
    });
  }

  addControl(): void {
    this.rolesFieldAsFormArray.push(this.role());
  }

  remove(i: number): void {
    this.rolesFieldAsFormArray.removeAt(i);
  }

  submit() {
    console.log(this.form.value)
  }

}

In this example, we have a form with role as a dynamic control. The *ngFor directive is used to iterate over the form's controls to render the control dynamically. When the form is submitted, the submit method is called, which logs the form's data to the console.

constructor(private fb: FormBuilder) {
    this.form = this.fb.group({
      email: [
        '',
        {
          validators: [Validators.required, Validators.email],
        },
      ],
      password: ['', [Validators.required, Validators.minLength(8)]],
      roles: this.fb.array([]),
    });

  }

In the above form, we are using the FormBuilder array method to create FormArray type control.

get rolesFieldAsFormArray(): any {
    return this.form.get('roles') as FormArray;
  }

This is the getter that returns roles from the form group as an array. Which we will be used to add/remove the control.

addControl(): void { this.rolesFieldAsFormArray.push(this.role()); } remove(i: number): void { this.rolesFieldAsFormArray.removeAt(i); }

These two are the main functions to add and remove control from formBuilder. We push control to the array to add the controller and remove control from the specific index using removeAt() method.

This is what the submitted form will look like.

Wrap-up

On running the application, you should now have a fully functional dynamic form. So, in this article, you learned about reactive forms and various classes of them. You also learned about FormArray to create a dynamic form.

I hope you found it useful. Suggestions and comments are welcome.