Search code examples
angulartypescriptangular-reactive-formsangular-forms

Angular - ngValue is not binding


ngValue will not bind the value unless you keep the reference of the same list. Is it correct?

This will not work:

this.myForm.get('user').patchValue(this.currentUser);

This will work:

const findIndex = this.user.findIndex(
  (item) => item.id == this.currentUser.id
);
this.myForm.get('user').patchValue(this.user[findIndex]);

Also, I came to one more property compareWith that can be used to bind as well.

This will work if I use it with compareWith.

this.myForm.get('user').patchValue(this.currentUser);

Playground Link: https://stackblitz.com/edit/angular-ivy-a4zbhn?file=src%2Fapp%2Fapp.component.ts


Solution

  • You should use [compareWith] Input property binding to the <select> element so that Angular could bind the value to the <select> by your defined comparison logic.

    .component.html

    <select formControlName="user" [compareWith]="compare">
      <option *ngFor="let us of user" [ngValue]="us">{{ us.name }}</option>
    </select>
    

    .component.ts

    compare(val1, val2) {
      return val1.id === val2.id;
    }
    

    Sample Solution on StackBlitz


    Updated Remarks:

    As Angular - SelectControlValueAccessor (Customizing option selection section) written,

    Angular uses object identity to select option.

    Without [compareWith], by default Angular will use object reference to select the option.

    Hence your inference with the first method is correct and workable as long you are providing the object with the exact reference as the object(s) is existed in [ngValue].

    const findIndex = this.user.findIndex(
        (item) => item.id == this.currentUser.id
    );
    
    this.myForm.get('user').patchValue(this.user[findIndex]);
    

    References

    Customizing option selection