Search code examples
angularangular-reactive-formsformbuilderformarray

How to add checkbox dynamically to angular forms (Angular 4)


I'm working on angular 4 form with Angular forms, how to dynamically add an input (checkbox) to the formArray after building the form.

ts:

signes_p = [
  { id: 'x1', name: 'bus' },
  { id: 'x2', name: 'car' }
];

ngOnInit() {
  const controls = this.signes_p.map(c => new FormControl(false));
  this.form = this.fb.group({
    signes: new FormArray(controls),
  });
}

addSigne(){
  if(this.new_signe && this.new_signe.trim().length>0){

    this.signes_p.push({
      id: this.new_signe,
      name: this.new_signe.replace(/^\w/, c => c.toUpperCase())
    })
  const controls = this.signes_p.map(c => new FormControl(false));
  const control = <FormArray>this.form.controls['signes'];
  var x = this.fb.group(controls[controls.length-1])
  control.push(x);
  }
}

html

<form [formGroup]="form" (ngSubmit)="onSubmit()">
      <div class="form-group" >
        <label for="signes" class="col-2 col-form-label" >Signes</label>  
          <div class="custom-control custom-checkbox" formArrayName="signes" *ngFor="let signe of form.controls.signes.controls; let i = index">
            <input type="checkbox" class="custom-control-input" [formControlName]="i" id="{{i}}">
            <label class="custom-control-label" for="{{i}}"> {{signes_p[i].name}}</label>
          </div>

          <div class="row" style="margin-top:20px;">
              <input class="form-control col-2" type="text" placeholder="Ajouter un autre..." [(ngModel)] = "new_signe" [ngModelOptions]="{standalone: true}" > 
              <a class="btn btn-success btn-sm" style="color: white;margin-left: 10px;" (click)="addSigne()"><i class="fa fa-plus" aria-hidden="true"></i></a>
          </div>        
      </div>
    ...
  <button class="btn btn-primary" type="submit" [disabled]="!form.valid">Enregistrer</button>   
</form>

i've also tried this medium_example, it caused these problems in html

control.registerOnChange is not a function

Must supply a value for form control with name: 'validator'.

Source link StackBlitz


Solution

  • There were a few things, which should become clear in light of the code below... on your stackblitz, replace the code in the following 2 files - check the console.log for resolution to your error also.

    replace the existing app.component.ts with the following

    import { Component } from '@angular/core';
    import { FormBuilder, FormGroup, FormArray, FormControl } from '@angular/forms';
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
    
      form: FormGroup
      constructor(private fb: FormBuilder, ) { this.initiate(); }
    
      insertedID: string;
      insertedName: string;
    
    
      fields = this.fb.group({
        elementArray: this.fb.array([this.createElementData('1', 'car')])
      });
    
      initiate() {
        const newRow2 = this.createElementData('2', 'bus');
        this.elementArray.push(newRow2);
      }
    
      createNew() {
        const newRow = this.createElementData(this.insertedID, this.insertedName);
        this.elementArray.push(newRow);
      }
    
      get elementArray(): FormArray {
        return this.fields.get("elementArray") as FormArray;
      }
    
      createElementData(passedID, passedName): FormGroup {
        if (passedID == 0 || !passedID) {
          passedID = this.elementArray.length + 1;
        }
        return this.fb.group({
          id: [passedID],
          name: [passedName],
          statusVal: false
        });
      }
    
      showData() {
        if (this.fields.value.elementArray.length > 0) {
          console.log(this.fields.value.elementArray);
        }
      }
    
    }
    
    export class Element {
      id: string;
      name: string;
      statusVal: boolean;
    }
    

    replace the existing app.component.html with the following

    <form [formGroup]="fields" class="example-form" (submit)="showData()">
      Signes:
      <div class='' formArrayName='elementArray' *ngFor="let item of fields.get('elementArray').controls; let i = index">
        <div [formGroupName]="i">
          <!-- <input type="text" formControlName="id" placeholder="Enter ID">  ID: [{{item.value.id}}] -->
          <input type="checkbox" formControlName="statusVal" placeholder="Enter Name">
          <!-- <input type="text" formControlName="name" placeholder="Enter Name"> -->{{item.value.name}}
    
        </div>
      </div>
      <div class="buttonDiv">
        <button type="submit" mat-raised-button color="primary">Enregistrer</button>
        <br/><br/> form status: <mark>{{fields.status}}</mark>
      </div>
    </form>
    
    <hr/>
    <!-- <input type='text' [(ngModel)]="insertedID" placeholder="ID du nouveau véhicule" /> -->
    <input type='text' [(ngModel)]="insertedName" placeholder="Ajouter un autre" />
    <button mat-raised-button color="primary" (click)="createNew()"> Ajouter un nouveau véhicule et checkbox </button>