Navigation

Sunday 25 August 2019

Add, Remove and Validate FormGroup dynamically to FormArray with Reactive Forms in Angular





Step 1: Create a component and service with the following command on your Visual Code Terminal or Node Js Command Prompt

D:\myProject> ng g c home

Step 2: Add the following CSS on your page.
Index.html


<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <title>Angular order by demo</title>
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
    <base href="/">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>

<body>
    <app-root></app-root>
</body>


</html>


Step 3: Copy and paste the following code on your created component. In my case i.e.
home.component.html


<div class="container">
    <div class="panel panel-primary">
        <div class="panel-heading">
            <h5>Add Multiple Employees.</h5>
        </div>
        <div class="panel-body">
            <h3></h3>
            <div class="card-body">
                <div class="row">
                    <div class="col-md-12">
                        <h5>Department Details</h5>
                        <hr>
                        <form [formGroup]="empForm" (ngSubmit)="onSubmit()">
                            <div class="custom-control custom-control-inline">
                                <label for="dNo" class="bmd-label-floating">Dept No</label>
                                <input type="text" class="form-control" id="dNo" disabled
                                       formControlName="DeptNo">
                            </div>
                            <div class="custom-control custom-control-inline">
                                <label for="dName" class="bmd-label-floating">Dept Name</label>
                                <input type="text" class="form-control" id="dName" disabled
                                       formControlName="DeptName">
                            </div>
                            <h5>Employees Detail</h5>
                            <hr>
                            <div formArrayName="EmpDetails" *ngFor="let emp of EmpData.controls; let i = index">
                                <hr *ngIf="i > 0">
                                <div [formGroupName]="i" class="row">
                                    <div class="col-sm-12" *ngIf="EmpData.length > 1">
                                        <a style="cursor: pointer;color:red" class="pull-right"
                                          title="Remove EmpDetails"
                                          (click)="removeEmpBtnClick(i,emp.get('empID').value)">
                                            <i class="fa fa-minus-square-o" aria-hidden="true"></i>
                                        </a>
                                    </div>
                                    <div class="col-md-4">
                                        <div class="form-group">
                                            <label for="'empId'+i" class="bmd-label-floating">Emp No</label>
                                            <input type="text" class="form-control" id="'empID'+i"
                                                   formControlName="empID"
                                                   [ngClass]="{'is-invalid': emp.get('empID').errors }">
                                            <div *ngIf="emp.get('empID').errors" class="invalid-feedback">
                                                <div *ngIf="emp.get('empID').errors.required">Required</div>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="col-md-4">
                                        <div class="form-group">
                                            <label for="'fName'+i" class="bmd-label-floating">FirstName</label>
                                            <input type="text" class="form-control" id="'fName'+i"
                                                   formControlName="firstName"
                                                   [ngClass]="{'is-invalid': emp.get('firstName').errors }">
                                            <div *ngIf="emp.get('firstName').errors" class="invalid-feedback">
                                                <div *ngIf="emp.get('firstName').errors.required">Required</div>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="col-md-4">
                                        <div class="form-group">
                                            <label for="'lName'+i" class="bmd-label-floating">LastName</label>
                                            <input type="text" class="form-control" id="'lName'+i"
                                                   (ngModelChange)="fnCheckFirstName($event,i)"
                                                   formControlName="lastName">
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="col-md-12 m-t-40 m-b-50">
                                <a style="cursor: pointer; float: right;" (click)="addEmpBtnClick();"
                                   class="text-primary">
                                    <i class="fa fa-plus"></i> Add More
                                </a>
                            </div>
                            <div class="form-group">
                                <button class="btn btn-primary">Register</button>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>


Step 4: Copy and paste the following code on your created component.
 home.component.ts

Note: Employee service has commented so that code runs flawlessly.
This service is used to get employee details and bind the employees OnInit function and also save the employee details to the database.

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators, FormArray, FormControl } from '@angular/forms';
//import { EmployeeService } from '../employee.service';


@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
  empForm: FormGroup;
  submitted = false;
  public EmpNo = 0;
  public employees = [];
  constructor(
    private formBuilder: FormBuilder,
    //private _empService: EmployeeService,
  ) { }

  ngOnInit() {
    this.empForm = this.formBuilder.group({
      DeptNo: ['12', Validators.required],
      DeptName: ['Account', Validators.required],
      EmpDetails: this.formBuilder.array([this.addEmpDetails()])
    });
   
    //Code to bind employee details OnInit
    //this.fnGetEmpDetails();
  }
  get f() { return this.empForm.controls; }
  get EmpData() { return <FormArray>this.empForm.get('EmpDetails'); }
  addEmpDetails(): FormGroup {
    this.EmpNo += 1
    return this.formBuilder.group({
      empID: [this.EmpNo,Validators.required],
      firstName: ['',Validators.required],
      lastName: ['']
    })
  }
  addEmpBtnClick() {
    debugger;
    (<FormArray>this.empForm.get('EmpDetails')).push(this.addEmpDetails());
  }
  removeEmpBtnClick(_index: number, _empID: number): void {
    debugger;
    if (_empID != 0) {
      (<FormArray>this.empForm.get('EmpDetails')).removeAt(_index);
    }
  }
  fnGetEmpDetails() {
    //this._empService.getEmployees()
    //  .subscribe(data => {
    //    this.employees = data
    //    this.empForm = this.formBuilder.group({
    //      DeptNo: [this.employees[0].DeptNo, Validators.required],
    //      DeptName: [this.employees[0].DeptName, Validators.required],
    //    });
    //    this.bindEmpDetails(this.employees);
    //  });
  }
  bindEmpDetails(_data: any) {
    let control = this.formBuilder.array([]);
    _data.forEach(x => {
      control.push(this.formBuilder.group({
        empID: [x.empID],
        firstName: [x.firstName == null ? "" : x.firstName],
        lastName: [x.lastName == null ? "" : x.lastName],
      }));
      this.empForm.setControl('EmpDetails', control);
    });

  }
  fnCheckFirstName(lastName: string, index: number) {
    debugger;
    let control = this.empForm.controls.EmpDetails.value;
    let fName = control[index].firstName;
    if (lastName == undefined || lastName == "" || lastName == null) {
      return false;
    }
    if (fName == null || fName == "") {
      const emp = (<FormArray>this.empForm.get('EmpDetails')).controls;
      const expirationMonth = emp[index].get('lastName');
      expirationMonth.setValue(null);
      expirationMonth.updateValueAndValidity();
      alert('First Name required')
    }
  }
  onSubmit() {
    this.submitted = true;
    // stop here if form is invalid
    if (this.empForm.invalid) {
      alert('Required field cannot be blank.')
      return;
    }
    let control = this.empForm.controls.EmpDetails.value;
    control.forEach(element => {
      let objEmp =
      {
        JobApplicationId: this.empForm.value.DeptNo,
        SecurityLicence: this.empForm.value.DeptName,
        EmpNo: element.EmpNo,
        firstName: element.firstName,
        lastName: element.lastName,
      }
      //Call your service to save the emp details, in forEach loop
      //this._empService.SaveEmpDetails(objEmp)
      //  .subscribe(e => {
      //    if (e == "0") {
      //      alert('SUCCESS!! :-)\n\n' + JSON.stringify(this.empForm.value))
      //    }
      //  });
    });

  }
}


2 comments: