Zephyr
Zephyr

Reputation: 73

patchValue returning only values of the last index

I have an issue while looping through and array, I'm getting all the index from this array correctly but when I use angular patchValue it updates all the inputs with the last index values and not with their respective values as shown :

enter image description here

I want every input to have theirs, for example, first input values should be "1" (left input => longueur) and "1" (right input => quantity)

enter image description here

I tried with .forEach but no success

CODE SAMPLE

component.ts .forEach

  ngOnInit() {
    this.requiredFields();
    this.service.checkExistQuot().subscribe(res => {
          this.quotDetails.forEach( (myArray, index) => {
              this.dropForm.patchValue({
                longueur: this.quotDetails[index].longueur,
                quantity: this.quotDetails[index].quantity
              })
             console.log(index);
          });
    });
  }

HTML, input example

<div class="products">
  <div class="d-flex flex-row" *ngFor="let products of selectedDiam;let i = index">
      <input class="number" formControlName="longueur" value="" (change)="postQuotationDatas(products.part_id)" type="number">
    </a>
    <input class="mb-1 flex1 checkbox" type="checkbox">
    <a class="tac flex1"></a>
    <a class="flex1 mb-1">
      <input class="number" value=""  formControlName="quantity" (change)="postQuotationDatas(products.part_id)" type="number">
    </a>
    <a class="flex1"></a>
  </div>
</div>

Upvotes: 0

Views: 724

Answers (3)

David
David

Reputation: 34455

Your problem is that you only have one form group,dropForm, with 2 controls: quantity and longueur. Even though you have multiple html inputs for longueur and quantity, they are share the same reference in the component

So, with your forEach loop, you are actually patching all your controls for each iteration. That's why you have the same value for all your controls, which is the value for the lasst object the loop went over.

Option #1

A possible solution is to have multiple form groups, like in this stackblitz example

component.ts

//dropForms initialisation
this.quotationDetails.map(() =>
{

let group = this.formBuilder.group(
  {
    longueur: [''],
    quantity: [''],
  });
  this.dropForms.push(group)
}

this.quotationDetails.forEach( (myArray, index) => {
        this.dropForms[index].patchValue({
          longueur: this.quotationDetails[index].longueur,

component.html

<div class="d-flex flex-row" *ngFor="let products of quotationDetails; let index=index"> 
    <form [formGroup]="dropForms[index]"> <!-- 1 form group per quotation -->

Option #2

The other solution, to have only 1 formGroup, is to give dynamic control names

component.ts

//Initialisation of dropForm
this.quotationDetails.forEach((val, index)=>
{
  group[`longueur_${index}`] = '';
  group[`quantity_${index}`] = ''
});
this.dropForm = this.formBuilder.group(
  group
)       

//Patch
this.quotationDetails.forEach( (myArray, index) => {
    let patchValue = {};
    patchValue[`longueur_${index}`] = this.quotationDetails[index].longueur;
    patchValue[`quantity_${index}`] = this.quotationDetails[index].quantity;
    this.dropForm.patchValue(patchValue);

component.html

<form [formGroup]="dropForm">
    <div class="products">
    <div class="d-flex flex-row" *ngFor="let products of quotationDetails; let index = index">
    <a>
      <input class="number"  formControlName="longueur_{{index}}"  value="" type="number">

Stackblitz example

Upvotes: 1

Souhail HARRATI
Souhail HARRATI

Reputation: 325

Example add FormControl to FormArray with FormBuilder:

FormArray - A FormArray aggregates the values of each child FormControl into an array.

in componenent ts:

const EMPLOYEE_FORM = {
  firstName: ['', Validators.required],
  lastName: ['', Validators.required],
  isActive : [false, Validators.required]
}

const COMPANY_FORM = {
  employees: new FormArray([], [Validators.required])
}
export class AppComponent  {
  form: FormGroup;

  constructor(private fb: FormBuilder) {
    this.form = this.fb.group(COMPANY_FORM);
  }

  get employees(): FormArray {
    return this.form.get('employees') as FormArray;
  }

  addEmployee() {
    const employee = this.fb.group(EMPLOYEE_FORM);
    this.employees.push(employee);
  }
}

in html

<div *ngFor="let item of employees.controls; let i = index;">
  <form [formGroup]="item">
    <input type="text"  formControlName="firstName" class="form-control" placeholder="FirstName">
    <input type="text"  formControlName="lastName" class="form-control" placeholder="LastName">
    <input class="checkbox" type="checkbox" formControlName="isActive">
  </form>
</div>
<button (click)="addEmployee()">add new employee</button>
<div *ngIf="employees.length > 0">
  {{employees.value | json}}
</div>

See this link: https://stackblitz.com/edit/add-input-to-formarray-with-frombuilder

Upvotes: 0

Tomasz Flis
Tomasz Flis

Reputation: 46

Use FormArray and wrap inputs in arrays.

Upvotes: 0

Related Questions