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>
Using NgModel Directive Angular has another way to get the selected value in the dropdown using the power of ngModel and two-way data binding. The ngModel is part of the forms module. We need to import it into the NgModule list in the app. module , which will be available in our app.
In Summary : Use [value] when you are binding to a string value and only a string value. Or you need access to the option value inside the HTML for automation purposes. Use [ngValue] when you are binding to any type and/or you want the entire option bound instead of just a string.
Use unique identifiers as values for dropdown options, which in your case is category ids. Now pass the category id from the portal object to ngModel directive to bind the value to dropdown. You can use ngModelChange directive to listen for category id value changes and update the same in portal object.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With