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;
}
As value
attribute of option
tag cannot store a whole object we will create a new property id
in the lUsers
array to keep track of the selected item.
HTML :
<select #selectElem (change)="setNewUser(selectElem.value)">
<option *ngFor="let user of lUsers" [value]="user.id">
{{user.Name}}
</option>
</select>
This will pass the unique id
to our setNewUser
function on change.
In your component.ts :
...
lUsers: any[] = [
{ id: 1, Name: 'Billy Williams', Gender: 'male' },
{ id: 2, Name: 'Sally Ride', Gender: 'female'}
];
curUser: any = this.lUsers[0]; // first will be selected by default by browser
...
setNewUser(id: any): void {
console.log(id);
// Match the selected ID with the ID's in array
this.curUser = this.lUsers.filter(value => value.id === parseInt(id));
console.log(this.curUser);
}
Here is the plnkr demo of the above code. Open your developer tools to view the console logs.
You can use [ngValue] instead of [value] on the -Elements.
It works for me.
I've found that information here: https://www.reddit.com/r/Angular2/comments/65run4/select_option_using_value_vs_ngvalue/
ANGULAR 6 SIMPLY DO THIS
HTML
<div class="col-3" style="float:left;padding-left: 18px !important;">
<label>Vehicle No.</label>
<div *ngIf="gpsDevicesArray && gpsDevicesArray.length > 0">
<select [ngModel]="selectedVehicle" style="padding: 7px;border-radius: 4px;"
(ngModelChange)="onVehicleNumberChange($event)">
<option *ngFor=" let device of gpsDevicesArray" [ngValue]="device">
{{device.vehicleNumber}}
</option>
</select>
</div>
</div>
TYPESCRIPT
// For intital Value ( put this line inside server calling function )
this.selectedVehicle = gpsDevicesArray[0];
// listener
onVehicleNumberChange(device) {
console.log("selectedVehicle ====", device);
}
HTML:
<select [formControl]="years">
<option value="">Select</option>
<option *ngFor="let year of yearsList" [ngValue]="year">{{year.value}}</option>
</select>
TS:
years = new FormControl('');
yearsList = [{id: 1, value: '2019'}, {id:2, value: '2020'}];
this.years.valueChanges.subscribe((year) => {
console.log(year)
});
RESULT:
you will get year object in console :)