Search code examples
angularngforangular-forms

How to get each input generated by * ngFor to have its own form control


I have a form, which has some inputs that are repeated with * ngFor, but they are repeated with the same "formControlName" So when one has an error, everyone has an error, and I would like to know if it is possible to get them to acquire their own formControl

component.html

<div fxFlexFill fxLayoutAlign="center center" *ngIf="sel.includes('Cobertor')">
                <mat-card fxFlex="99%" class="mat-elevation-z3">
                  <mat-card-header>
                    <mat-card-title>Cobertores</mat-card-title>
                    <mat-card-subtitle>a {{element.name.split(" ")[0]}}</mat-card-subtitle>
                  </mat-card-header>
                  <mat-card-content>
                    <div fxLayoutAlign="center center" fxLayout="row" fxLayoutGap="0.5%"
                      *ngFor="let elm of cobertorCount">
                      <mat-form-field fxFlex="80%" appearance="fill">
                        <mat-label>Añadir cobertor</mat-label>
                        <input formControlName="cobertor" type="number" matInput
                          placeholder="Ingresa la cantidad a añadir" #input [required]="sel.includes('Cobertor')">
                      </mat-form-field>
                      <mat-form-field appearance="fill" fxFlex="20%">
                        <mat-label>Tamaño</mat-label>
                        <mat-select>
                          <mat-option *ngFor="let size of sizes" [value]="size.value">
                            {{size.viewValue}}
                          </mat-option>
                        </mat-select>
                      </mat-form-field>
                    </div>
                  </mat-card-content>
                  <!--Boton para añadir nuevo cobertor-->
                  <mat-card-actions>
                    <button mat-flat-button color="primary" (click)="add('cobertor')">
                      <mat-icon>add</mat-icon>
                    </button>
                    <button mat-flat-button color="warn" (click)="remove('cobertor')">
                      <mat-icon>remove</mat-icon>
                    </button>
                  </mat-card-actions>
                </mat-card>
              </div>

here the inputs are shown in a material card, which is only visible when a select is activated, by default there is always an input, but you can add 2 more

component.ts

dataForm = new FormGroup({
    cobertor: new FormControl(null, Validators.required)
  })

sizes: any[] = [
    { value: 'matrimonial', viewValue: 'Matrimonial' },
    { value: 'individual', viewValue: 'Individual' },
    { value: 'kingsize', viewValue: 'KingSize' }
  ];

cobertorCount: any = [1];

sel = []

add(to: string) {
    switch (to) {
      case "cobertor":
        if (this.cobertorCount.length >= 3) {
          alert("Maximo")
          break;
        }
        this.cobertorCount.push(this.cobertorCount.length + 1);
        break;
}

I think it is all the most important code


Solution

  • to keep same formcontrolname we must implement it inside formarray.

    <form [formGroup]="dataForm">
      <div formArrayName="dataArray" *ngFor="let item of dataForm.get('dataArray').controls; let i = index;">
        <div [formGroupName]="i">
         <input formControlName="cobertor" type="number" matInput placeholder="Ingresa la cantidad a añadir" #input [required]="sel.includes('Cobertor')">
        </div>
      </div>
    </form>
    
    ngOnInit(){
      dataForm = this.formbuilder.group({
        dataArray: this.fb.array([])
      })
    }
    
    setFormValues(){
      dataForm = this.formbuilder.group({
        dataArray: initFormArray(arrayValues)
      })
    }
    
    initFormArray(units): FormArray{
      const fArray = <FormArray>this.exampleForm.controls['dataArray'];
      units.forEach(unit=>{
        fArray.push(this.formBuilder.push({
          cobertor: [unit.value]
        }))
      })
      return fArray;
    }