I'd like to bind a select element to a list of objects -- which is easy enough:
@Component({
selector: 'myApp',
template:
`<h1>My Application</h1>
<select [(ngModel)]="selectedValue">
<option *ngFor="#c of countries" value="c.id">{{c.name}}</option>
</select>`
})
export class AppComponent{
countries = [
{id: 1, name: "United States"},
{id: 2, name: "Australia"}
{id: 3, name: "Canada"},
{id: 4, name: "Brazil"},
{id: 5, name: "England"}
];
selectedValue = null;
}
In this case, it appears that selectedValue
would be a number -- the id of the selected item.
However, I'd actually like to bind to the country object itself so that selectedValue
is the object rather than just the id. I tried changing the value of the option like so:
<option *ngFor="#c of countries" value="c">{{c.name}}</option>
but this does not seem to work. It seems to place an object in my selectedValue
-- but not the object that I'm expecting. You can see this in my Plunker example.
I also tried binding to the change event so that I could set the object myself based on the selected id; however, it appears that the change event fires before the bound ngModel is updated -- meaning I don't have access to the newly selected value at that point.
Is there a clean way to bind a select element to an object with Angular 2?
<h1>My Application</h1>
<select [(ngModel)]="selectedValue">
<option *ngFor="let c of countries" [ngValue]="c">{{c.name}}</option>
</select>
NOTE: you can use [ngValue]="c"
instead of [ngValue]="c.id"
where c is the complete country object.
[value]="..."
only supports string values
[ngValue]="..."
supports any type
update
If the value
is an object, the preselected instance needs to be identical with one of the values.
See also the recently added custom comparison https://github.com/angular/angular/issues/13268 available since 4.0.0-beta.7
<select [compareWith]="compareFn" ...
Take care of if you want to access this
within compareFn
.
compareFn = this._compareFn.bind(this);
// or
// compareFn = (a, b) => this._compareFn(a, b);
_compareFn(a, b) {
// Handle compare logic (eg check if unique ids are the same)
return a.id === b.id;
}
This could help:
<select [(ngModel)]="selectedValue">
<option *ngFor="#c of countries" [value]="c.id">{{c.name}}</option>
</select>
let
instead of #
@sea-kg
You can do this too without the need to use [(ngModel)]
in your <select>
tag
Declare a variable in your ts file
toStr = JSON.stringify;
and in you template do this
<option *ngFor="let v of values;" [value]="toStr(v)">
{{v}}
</option>
and then use
let value=JSON.parse(event.target.value)
to parse the string back into a valid JavaScript object
It worked for me:
Template HTML:
I added (ngModelChange)="selectChange($event)"
to my select
.
<div>
<label for="myListOptions">My List Options</label>
<select (ngModelChange)="selectChange($event)" [(ngModel)]=model.myListOptions.id >
<option *ngFor="let oneOption of listOptions" [ngValue]="oneOption.id">{{oneOption.name}}</option>
</select>
</div>
On component.ts:
listOptions = [
{ id: 0, name: "Perfect" },
{ id: 1, name: "Low" },
{ id: 2, name: "Minor" },
{ id: 3, name: "High" },
];
An you need add to component.ts
this function:
selectChange( $event) {
//In my case $event come with a id value
this.model.myListOptions = this.listOptions[$event];
}
Note: I try with [select]="oneOption.id==model.myListOptions.id"
and not work.
============= Another ways can be: =========
Template HTML:
I added [compareWith]="compareByOptionId
to my select
.
<div>
<label for="myListOptions">My List Options</label>
<select [(ngModel)]=model.myListOptions [compareWith]="compareByOptionId">
<option *ngFor="let oneOption of listOptions" [ngValue]="oneOption">{{oneOption.name}}</option>
</select>
</div>
On component.ts:
listOptions = [
{ id: 0, name: "Perfect" },
{ id: 1, name: "Low" },
{ id: 2, name: "Minor" },
{ id: 3, name: "High" },
];
An you need add to component.ts
this function:
/* Return true or false if it is the selected */
compareByOptionId(idFist, idSecond) {
return idFist && idSecond && idFist.id == idSecond.id;
}
[ngModel]
and then set your model manually in your custom change callback defined in (ngModelChange)
.
Just in case someone is looking to do the same using Reactive Forms:
<form [formGroup]="form">
<select formControlName="country">
<option *ngFor="let country of countries" [ngValue]="country">{{country.name}}</option>
</select>
<p>Selected Country: {{country?.name}}</p>
</form>
Check the working example here
For me its working like this, you can console event.target.value
.
<select (change) = "ChangeValue($event)" (ngModel)="opt">
<option *ngFor=" let opt of titleArr" [value]="opt"></option>
</select>
The key is to use a two way binding in the select
via [(ngModel)]
and use [ngValue]
in each option
.
You can even have a default null option and it works with Angular 12.
<select name="typeFather" [(ngModel)]="selectedType">
<option [ngValue]="null">Select a type</option>
<option *ngFor="let type of types" [ngValue]="type">{{type.title}}</option>
</select>
That approach is always going to work, however if you have a dynamic list, make sure you load it before the model.
You Can Select the Id using a Function
<option *ngFor="#c of countries" (change)="onchange(c.id)">{{c.name}}</option>
Create another getter for selected item
<form [formGroup]="countryForm">
<select formControlName="country">
<option *ngFor="let c of countries" [value]="c.id">{{c.name}}</option>
</select>
<p>Selected Country: {{selectedCountry?.name}}</p>
</form>
In ts :
get selectedCountry(){
let countryId = this.countryForm.controls.country.value;
let selected = this.countries.find(c=> c.id == countryId);
return selected;
}
In app.component.html
:
<select type="number" [(ngModel)]="selectedLevel">
<option *ngFor="let level of levels" [ngValue]="level">{{level.name}}</option>
</select>
And app.component.ts
:
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
levelNum:number;
levels:Array<Object> = [
{num: 0, name: "AA"},
{num: 1, name: "BB"}
];
toNumber(){
this.levelNum = +this.levelNum;
console.log(this.levelNum);
}
selectedLevel = this.levels[0];
selectedLevelCustomCompare = {num: 1, name: "BB"}
compareFn(a, b) {
console.log(a, b, a && b && a.num == b.num);
return a && b && a.num == b.num;
}
}
Also, if nothing else from given solutions doesn't work, check if you imported "FormsModule" inside of "AppModule", that was a key for me.
You can get selected value also with help of click() by passing the selected value through the function
<md-select placeholder="Select Categorie"
name="Select Categorie" >
<md-option *ngFor="let list of categ" [value]="list.value" (click)="sub_cat(list.category_id)" >
{{ list.category }}
</md-option>
</md-select>
use this way also..
<h1>My Application</h1>
<select [(ngModel)]="selectedValue">
<option *ngFor="let c of countries" value="{{c.id}}">{{c.name}}</option>
</select>
Attention Angular 2+ users: for some reason, [value] does not work on elements. use [ngModel] instead.
<select [ngModel]="selectedCountry">
<option *ngFor="let country of countries" [value]="country">{{country.name}}</option>
</select>
Tested on Angular 11. I need an extra object 'typeSelected'. Pay attention I'm not using [(ngValue)] as other answers do:
<mat-select formControlName="type" [(value)]="typeSelected"
[compareWith]="typeComparation">
<mat-option *ngFor="let myType of allSurveysTypes" [value]="myType">
{{myType.title}}
</mat-option>
</mat-select>
//Declaration.
typeSelected: SurveyType;
...
//Assigning variable 'type' of object 'survey' to 'typeSelected'.
this.typeSelected = survey?.type;
...
//Function to compare SurveyType objects.
typeComparation = ( option, value ) => {
if (option && value) {
return option.id === value.id;
}
}
This code is very simple:
<select class="form-control" id="marasemaat" [(ngModel)]="fullNamePresentor"
[formControl]="stateControl" (change)="onSelect($event.target.value)">
<option *ngFor="let char of programInfo1;let i = index;"
onclick="currentSlide(9,false)"
value={{char.id}}>{{char.title + " "}} ----> {{char.name + " "+ char.family }} ---- > {{(char.time.split('T', 2)[1]).split(':',2)}}</option>
</select>
Success story sharing
ngValue
and not justvalue
, even if the select displays the correct text.selectedValue
than forc
of (the default item). A different object even with the same properties and values doesn't work, it has to be the same object instance.[ngValue]
instead of[value]
was the key for me. Thanks.