Create nested forms or add/remove forms dynamically with FormArray angular 13
Today, we are going to learn about nested forms or add/remove forms dynamically with FormArray
in angular.
For this tutorial, we are going to build a to-do app in which we can add new tasks, remove old ones and mark them as finished.Here is the final output To-Do App
Here is the final output To-Do App
So, let’s start
1. Create the to-do form component and listing component
ng g c form
ng g c list
2. On the listing page we will use the add task button because we want to implement angular FormArray
. It will help us to add multiple tasks at a time.
We are going to use bootstrap css for this project. So, I just download the bootstrap file added to style.scss
as below
/* You can add global styles to this file, and also import other style files */ @import './assets/css/bootstrap.css';
Then in the form.component.ts
, I have used a FormGroup
, FormBuilder
and used FormArray
as given in the below code.
import { Component, OnInit } from '@angular/core'; import { FormArray, FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { CommonService } from 'src/app/common.service'; @Component({ selector: 'app-form', templateUrl: './form.component.html', styleUrls: ['./form.component.scss'] }) export class FormComponent implements OnInit { todoForm: FormGroup; constructor( public commonService: CommonService, private fb: FormBuilder ) { this.todoForm = this.fb.group({ todos: this.fb.array([]) }) this.addTodo(); } ngOnInit(): void { } get todos() { return this.todoForm.controls['todos'] as FormArray; } addTodo() { const todo = new FormGroup({ title: new FormControl(''), descr: new FormControl('') }) this.todos.push(todo); } removeTodo(index: number) { this.todos.removeAt(index); } submit() { this.commonService.logger('form submitted', this.todoForm.value) } }
And then in the component html template code
<div class="main-content container bg-green"> <form (ngSubmit)="submit()" [formGroup]="todoForm" class="mt-4"> <ng-container formArrayName="todos"> <div *ngFor="let todo of todos.controls; let i = index;"> <div [formGroupName]="i" class="border p-3 my-3"> <div> <label for="title">Title</label> <input class="form-control" type="text" formControlName="title" id="title"> </div> <div> <label for="descr">Description</label> <input class="form-control" type="text" formControlName="descr" id="descr"> </div> <div class="d-flex justify-content-end mt-3"> <button class="btn btn-primary" type="button" (click)="addTodo()">Add</button> <button class="btn btn-danger mx-3" type="button" (click)="removeTodo(i)" *ngIf="todos.length>1" > Remove </button> </div> </div> </div> </ng-container> <button class="btn btn-primary" type="submit">Submit</button> </form> </div>
Here it needs to notice that we have given FormArrayName
and then under this we have loop over the todos array which contains the form groups and then in the FormGroupName
we have used the index of FormGroup
because that is the actual index in the todos array.
If we just use the loop over the todos array and then use the todo as formGroup as you can see in the code above. Then we encountered this error:
“AbstractControl’ is missing the following properties from type ‘FormGroup’: controls, registerControl, addControl, removeControl, and 3 more.”
Solution: we have solved this by using the above technique, one is wrap the form controls with FormArrayName
and then use index as FormGroupName
.
Your assignment is to add form validation in this form.
Hope you found it useful. See you in the next tutorial.
Thank you. This was very useful as a introduction to FormArray.