How can I get new selection in "select" in Angular 2?

AngularTypescriptHtml Select

Angular Problem Overview


I am using Angular 2 (TypeScript).

I want to do something with the new selection, but what I get in onChange() is always the last selection. How can I get the new selection?

<select [(ngModel)]="selectedDevice" (change)="onChange($event)">
   <option *ngFor="#i of devices">{{i}}</option>
</select>
onChange($event) {
    console.log(this.selectedDevice);
    // I want to do something here with the new selectedDevice, but what I
    // get here is always the last selection, not the one I just selected.
}

Angular Solutions


Solution 1 - Angular

If you don't need two-way data-binding:

<select (change)="onChange($event.target.value)">
    <option *ngFor="let i of devices">{{i}}</option>
</select>

onChange(deviceValue) {
    console.log(deviceValue);
}

For two-way data-binding, separate the event and property bindings:

<select [ngModel]="selectedDevice" (ngModelChange)="onChange($event)" name="sel2">
    <option [value]="i" *ngFor="let i of devices">{{i}}</option>
</select>

export class AppComponent {
  devices = 'one two three'.split(' ');
  selectedDevice = 'two';
  onChange(newValue) {
    console.log(newValue);
    this.selectedDevice = newValue;
    // ... do other stuff here ...
}

If devices is array of objects, bind to ngValue instead of value:

<select [ngModel]="selectedDeviceObj" (ngModelChange)="onChangeObj($event)" name="sel3">
  <option [ngValue]="i" *ngFor="let i of deviceObjects">{{i.name}}</option>
</select>
{{selectedDeviceObj | json}}

export class AppComponent {
  deviceObjects = [{name: 1}, {name: 2}, {name: 3}];
  selectedDeviceObj = this.deviceObjects[1];
  onChangeObj(newObj) {
    console.log(newObj);
    this.selectedDeviceObj = newObj;
    // ... do other stuff here ...
  }
}

Plunker - does not use <form>
Plunker - uses <form> and uses the new forms API

Solution 2 - Angular

You can pass the value back into the component by creating a reference variable on the select tag #device and passing it into the change handler onChange($event, device.value) should have the new value

<select [(ng-model)]="selectedDevice" #device (change)="onChange($event, device.value)">
    <option *ng-for="#i of devices">{{i}}</option>
</select>

onChange($event, deviceValue) {
    console.log(deviceValue);
}

Solution 3 - Angular

Just use [ngValue] instead of [value]!!

export class Organisation {
  description: string;
  id: string;
  name: string;
}
export class ScheduleComponent implements OnInit {
  selectedOrg: Organisation;
  orgs: Organisation[] = [];

  constructor(private organisationService: OrganisationService) {}

  get selectedOrgMod() {
    return this.selectedOrg;
  }

  set selectedOrgMod(value) {
    this.selectedOrg = value;
  }
}


<div class="form-group">
      <label for="organisation">Organisation
      <select id="organisation" class="form-control" [(ngModel)]="selectedOrgMod" required>
        <option *ngFor="let org of orgs" [ngValue]="org">{{org.name}}</option>
      </select>
      </label>
</div>

Solution 4 - Angular

I ran into this problem while doing the Angular 2 forms tutorial (TypeScript version) at https://angular.io/docs/ts/latest/guide/forms.html

The select/option block wasn't allowing the value of the selection to be changed by selecting one of the options.

Doing what Mark Rajcok suggested worked, although I'm wondering if there's something I missed in the original tutorial or if there was an update. In any case, adding

onChange(newVal) {
	this.model.power = newVal;
}

to hero-form.component.ts in the HeroFormComponent class

and

(change)="onChange($event.target.value)"

to hero-form.component.html in the <select> element made it work

Solution 5 - Angular

use selectionChange in angular 6 and above. example (selectionChange)= onChange($event.value)

Solution 6 - Angular

I was has same problem and i solved using the below code :

(change)="onChange($event.target.value)"

Solution 7 - Angular

In Angular 8 you can simply use "selectionChange" like this:

 <mat-select  [(value)]="selectedData" (selectionChange)="onChange()" >
  <mat-option *ngFor="let i of data" [value]="i.ItemID">
  {{i.ItemName}}
  </mat-option>
 </mat-select>

Solution 8 - Angular

Another option is to store the object in value as a string:

<select [ngModel]="selectedDevice | json" (ngModelChange)="onChange($event)">
    <option [value]="i | json" *ngFor="let i of devices">{{i}}</option>
</select>

component:

onChange(val) {
    this.selectedDevice = JSON.parse(val);
}

This was the only way I could get two way binding working to set the select value on page load. This was because my list that populates the select box was not the exact same object as my select was bound to and it needs to be the same object, not just same property values.

Solution 9 - Angular

Angular 7/8

As of angular 6,the use of ngModel input property with reactive forms directive have been deprecated and removed altogether in angular 7+. Read official doc here.

Using reactive form approach you can get/set selected data as;

      //in your template
 <select formControlName="person" (change)="onChange($event)"class="form-control">
    <option [value]="null" disabled>Choose person</option>
      <option *ngFor="let person of persons" [value]="person"> 
        {{person.name}}
    </option>
 </select> 


 //in your ts
 onChange($event) {
    let person = this.peopleForm.get("person").value
    console.log("selected person--->", person);
    // this.peopleForm.get("person").setValue(person.id);
  }

Solution 10 - Angular

<mat-form-field>
<mat-select placeholder="Vacancies" [(ngModel)]="vacanciesSpinnerSelectedItem.code" (ngModelChange)="spinnerClick1($event)"
    [ngModelOptions]="{standalone: true}" required>
    <mat-option *ngFor="let spinnerValue of vacanciesSpinnerValues" [value]="spinnerValue?.code">{{spinnerValue.description}}</mat-option>
</mat-select>

I used this for angular Material dropdown. works fine

Solution 11 - Angular

I tried all the suggestions and nothing works for me.

Imagine the situation: you need a 2-way binding and you have a lookup with NUMBER values and you want to fill your SELECT with the values from this lookup and highlight the chosen option.

Using [value] or (ngModelChange) is a no-go, because you won't be able to select the chosen option after user initiated the change: [value] considers everything a string, as to (ngModelChange) - it obviously should not be used when user initiates the change, so it ruins the proper selection. Using [ngModel] guarantees the fixed format of received VALUE as INDEX: VALUE and it's easy to parse it correspondingly, HOWEVER once again - it ruins the selected option.

So we go with [ngValue] (which will take care of proper types), (change) and... [value], which guarantees the handler receives VALUE, not a DISPLAYED VALUE or INDEX: VALUE :) Below is my working clumsy solution:

  <select
    class="browser-default custom-select"
    (change)="onEdit($event.target.value)"
  >
    <option [value]="">{{
      '::Licences:SelectLicence' | abpLocalization
    }}</option>
    <ng-container *ngIf="licencesLookupData$ | async">
      <option
        *ngFor="let l of licencesLookupData$ | async"
        [ngValue]="l.id"
        [value]="l.id"
        [selected]="l.id == selected.id"
      >
        {{ l.id }} &nbsp;&nbsp; {{ l.displayName | defaultValue }}
      </option>
    </ng-container>
  </select>

  onEdit(idString: string) {
    const id = Number(idString);
    if (isNaN(id)) {
      this.onAdd();
      return;
    }
    this.licencesLoading = true;
    this.licencesService
      .getById(id)
      .pipe(finalize(() => (this.licencesLoading = false)), takeUntil(this.destroy))
      .subscribe((state: Licences.LicenceWithFlatProperties) => {
        this.selected = state;
        this.buildForm();
        this.get();
      });
  }

Solution 12 - Angular

latest ionic 3.2.0 have modified (change) to (ionChange)

eg: HTML

<ion-select (ionChange)="function($event)"> <ion-option>1<ion-option>
</ion-select>

TS

function($event){
// this gives the selected element
 console.log($event);

}

Solution 13 - Angular

In Angular 5 I did with the following way. get the object $event.value instead of $event.target.value

<mat-form-field color="warn">
   <mat-select (ngModelChange)="onChangeTown($event)" class="form-width" formControlName="branch" [(ngModel)]="branch" placeholder="Enter branch">
     <mat-option *ngFor="let branch of branchs" [value]="branch.value">
                  {{ branch.name }}
     </mat-option>
   </mat-select>
</mat-form-field>

onChangeTown(event): void {
  const selectedTown = event;
  console.log('selectedTown: ', selectedTown);
}

Solution 14 - Angular

From angular 7 and up, since ngModel is deprecated, we can simply use the control to get the new selected value very easily in a reactive way.

Example:

<form [formGroup]="frmMyForm">
  <select class="form-control" formControlName="fieldCtrl">
    <option value=""></option>
    <option value="val1">label val 1</option>
    <option value="val2">label val 2</option>
    <option value="val3">label val 3</option>
  </select>
</form>
this.frmMyForm.get('fieldCtrl').valueChanges.subscribe( value => {
  this.selectedValue = value;
});

By using this fully reactive way, we can upgrade older angular application version to newer ones more easily.

Solution 15 - Angular

If you don't need two-way data-binding:

<select (change)="updateSorting($event)">
  <option disabled selected>Sorting</option>
  <option value="pointDes">pointDes</option>
  <option value="timeDes">timeDes</option>
  <option value="timeAsc">timeAsc</option>
  <option value="pointAsc">pointAsc</option>
</select>
updateSorting(e: any) {
  // console.log((e.target as HTMLSelectElement)?.value); // also work
  console.log(e.target.value);
}

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
QuestionHongbo MiaoView Question on Stackoverflow
Solution 1 - AngularMark RajcokView Answer on Stackoverflow
Solution 2 - AngularBroccoView Answer on Stackoverflow
Solution 3 - Angularrobert kingView Answer on Stackoverflow
Solution 4 - AngularjariskyView Answer on Stackoverflow
Solution 5 - AngularvalentineView Answer on Stackoverflow
Solution 6 - AngularAbd AbughazalehView Answer on Stackoverflow
Solution 7 - AngularB.HabibzadehView Answer on Stackoverflow
Solution 8 - Angularkravits88View Answer on Stackoverflow
Solution 9 - Angular7guyoView Answer on Stackoverflow
Solution 10 - AngularApurvView Answer on Stackoverflow
Solution 11 - AngularAlexanderView Answer on Stackoverflow
Solution 12 - AngularskidView Answer on Stackoverflow
Solution 13 - AngularKumaresan PerumalView Answer on Stackoverflow
Solution 14 - AngularHDJEMAIView Answer on Stackoverflow
Solution 15 - AngulartinystoneView Answer on Stackoverflow