Binding select element to object in Angular

HtmlAngular

Html Problem Overview


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?

Html Solutions


Solution 1 - Html

<h1>My Application</h1>
<select [(ngModel)]="selectedValue">
  <option *ngFor="let c of countries" [ngValue]="c">{{c.name}}</option>
</select>

StackBlitz example

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;
}

Solution 2 - Html

This could help:

<select [(ngModel)]="selectedValue">
  <option *ngFor="#c of countries" [value]="c.id">{{c.name}}</option>
</select>

Solution 3 - Html

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

Solution 4 - Html

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;
 }

Solution 5 - Html

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

[1]: https://stackblitz.com/edit/angular-ibmdtl "here"

Solution 6 - Html

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>

Solution 7 - Html

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.

Solution 8 - Html

You Can Select the Id using a Function

<option *ngFor="#c of countries" (change)="onchange(c.id)">{{c.name}}</option>

Solution 9 - Html

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;
}

Solution 10 - Html

Also, if nothing else from given solutions doesn't work, check if you imported "FormsModule" inside of "AppModule", that was a key for me.

Solution 11 - Html

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;
  }
}

Solution 12 - Html

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>

Solution 13 - Html

use this way also..

<h1>My Application</h1>
<select [(ngModel)]="selectedValue">
     <option *ngFor="let c of countries" value="{{c.id}}">{{c.name}}</option>
 </select>

Solution 14 - Html

Attention Angular 2+ users: for some reason, [value] does not work on

Solution 15 - Html

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;
  }
}

Solution 16 - Html

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>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRHarrisView Question on Stackoverflow
Solution 1 - HtmlGünter ZöchbauerView Answer on Stackoverflow
Solution 2 - HtmlCarolina FaedoView Answer on Stackoverflow
Solution 3 - HtmlRahul KumarView Answer on Stackoverflow
Solution 4 - HtmlJose Carlos Ramos CarmenatesView Answer on Stackoverflow
Solution 5 - HtmlelvinView Answer on Stackoverflow
Solution 6 - Htmlnano devView Answer on Stackoverflow
Solution 7 - HtmlJack SowellView Answer on Stackoverflow
Solution 8 - HtmlEng.GabrView Answer on Stackoverflow
Solution 9 - HtmlRafiView Answer on Stackoverflow
Solution 10 - Htmlnikola.maksimovicView Answer on Stackoverflow
Solution 11 - HtmlMojtaba NavaView Answer on Stackoverflow
Solution 12 - HtmlJose KjView Answer on Stackoverflow
Solution 13 - HtmlRathinavelView Answer on Stackoverflow
Solution 14 - HtmlmamashareView Answer on Stackoverflow
Solution 15 - HtmlfuegonjuView Answer on Stackoverflow
Solution 16 - HtmlMojtaba NavaView Answer on Stackoverflow