'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 1:[1]

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1