I know that similar questions have been asked, but I've found none with a good answer. I want to create a select list in an Angular form, where the value for each option is an object. Also, I do NOT want to use 2 way data binding. e.g. if my Component has these fields:
lUsers: any[] = [ { Name: 'Billy Williams', Gender: 'male' }, { Name: 'Sally Ride', Gender: 'female'} ]; curUser: any;
I would like my HTML template to contain this:
<select #selectElem (change)="setNewUser(selectElem.value)"> <option *ngFor="let user of lUsers" [ngValue]="user"> {{user.Name}} </option> </select>
With this code, though, my setNewUser() function receives the contents of the selected user's Name field. Why it picks that specific field, I have no idea. What I expect is that it would receive the "value" of the selected option, which I specifically set to a user object.
Note that I used ngValue instead of value in the option. That was by suggestion of others on SO. If I use value instead, what happens is that the object gets converted to the string '[Object object]', which is what setNewUser() receives, which is useless.
FYI, I'm working on Windows 10, using angular 4.0.0 with @angular/cli 1.1.2. Here is the setNewUser() method:
setNewUser(user: User): void { console.log(user); this.curUser = user; } // setNewUser()
I am determining just what exactly is being passed to it both my logging it, and also including this on the template: <pre>{{curUser}}</pre>
I'm currently using [ngValue]
and it stores objects just fine.
The explanation as to why you experienced issues using (change)
instead of (ngModelChange)
can be found in this question
So, since you've already used [ngValue]
, you probably want to do something like this, where you will only use one way binding in order to be able to use the ngModelChange directive:
<select (ngModelChange)="setNewUser($event)" (ngModel)="lUsers">
<option *ngFor="let user of lUsers" [ngValue]="user">
{{user.Name}}
</option>
</select>
And your ts file will capture the event and receive the User object without needing to track it by id, basically reusing your old method will be good enough:
setNewUser(user: User): void {
console.log(user);
this.curUser = user;
}
UPDATE 16/06/2020:
Always depending on your use case you may need to use square brackets instead of round here: (ngModel)="lUsers
. For the particular case the OP stated, round brackets was the right choice. A clear and detailed description of the difference between square/round and banana box can be found in this answer from Angular guru Günter Zöchbauer