Search code examples
angularformbuilderformarray

Can't set array values in select elements using Formbuilder in Angular


I have this edit function. Only the select element does not update the value

invoice-update.component.ts

onUpdate(invoice) {
 console.log(invoice.customer)

 const control = <FormArray>this.form.controls['purchases'];
 control.controls = [];

 this.form.controls['$key'].setValue(invoice.$key);
 this.form.controls['customer'].setValue(invoice.customer);//this is the problem

 for (let i in invoice.purchases) {
   const product = (invoice.purchases[i].product);
   const quantity = (invoice.purchases[i].quantity);
   this.addPurchase(product);
   control.at(+i).get('quantity').setValue(quantity);
 }
}

Although the value is set in the select element, it does not allow updating the value, because it expects an array

Stackblitz


Solution

  • It is not updating because your Invoice model accept Customer object but you are passing just a name.

    export class IInvoice {
      $key?: string;
      invoiceNumber?: number;
      createdAt?: string;
      modifiedAt?:string;
      uid?: string;
    
      customer: Customer; // Currently you are passing string to this key.
      purchases: Purchase[];
      totalPrice: number;
    }
    

    Replace item.name by item. Update your select code from this:

     <select class="form-control custom-select" id="customer" formControlName="customer">
             <option [ngValue]="true">-Customer-</option>
    
             <option [ngValue]="item.name" *ngFor="let item of customerList" >{{item.name}} {{item.lastname}}</option>
     </select>
    

    to this:

     <select class="form-control custom-select" id="customer" formControlName="customer">
             <option [ngValue]="true">-Customer-</option>
    
             <option [ngValue]="item" *ngFor="let item of customerList" >{{item.name}} {{item.lastname}}</option>
     </select>
    

    And then it will work.

    To set selected customer as default value in dropdown, you can use compareWith property. This property accepts function parameter. Just add following property in select tag:-

    [compareWith]="compareFn"
    

    And define compareFn function like this:-

    compareFn(c1: any, c2:any): boolean {
       return c1 && c2 ? c1.name === c2.name : c1 === c2;
    } 
    

    Now default customer should be set as expected based on selected data.