Question

How to Get the Selected Value from a Select in Angular 2

typescriptangularhtml-select

Question

In Angular 2 with TypeScript, how can you access the newly selected value from a <select> element?

In the following example, the onChange() handler is called when the selection changes, but this.selectedDevice appears to contain the previous value instead of the newly selected one:

<select [(ngModel)]="selectedDevice" (change)="onChange($event)">
  <option *ngFor="let i of devices">{{ i }}</option>
</select>
onChange($event: Event) {
  console.log(this.selectedDevice);
  // I want to work with the newly selected device here,
  // but this logs the previous selection instead.
}

How do you get the current selected value when the user chooses a new option?

Short Answer

By the end of this page, you will understand why a native (change) event can feel out of sync with Angular's two-way binding, and how to correctly get the new selected value from a <select> using ngModelChange, template references, or the event target.

Concept

In Angular forms, a <select> can be connected to a component property using [(ngModel)]. This is called two-way binding.

<select [(ngModel)]="selectedDevice">

This means:

  • Angular writes the component value into the <select>
  • Angular updates the component property when the user picks a new option

The confusion usually comes from mixing:

  • the native DOM (change) event
  • Angular's [(ngModel)]
  • Angular's (ngModelChange) event

Why this matters

When you use (change), you are listening to the browser's native event from the <select> element. That event gives you access to the DOM event object, but depending on how you read your component property, it may not yet look updated in the way you expect.

Angular also provides (ngModelChange), which is specifically designed to work with ngModel. It emits the new value directly.

The key idea

If your goal is:

  • "Give me the newly selected value"

then the most Angular-friendly approach is:

<select [(ngModel)]="selectedDevice" (ngModelChange)="onChange($event)">

Here, $event is the new selected value itself.

This matters in real projects because form controls are everywhere:

  • dropdown filters
  • settings pages
  • product selectors
  • status updates
  • admin dashboards

Understanding the difference between DOM events and Angular form events helps you avoid stale values and write clearer code.

Mental Model

Think of a <select> as a form control with two messengers:

  • The browser messenger says: "The user changed something in the DOM."
  • The Angular messenger says: "The model value is now this new value."

If you listen to the browser messenger with (change), you may need to manually read the value from the event target.

If you listen to the Angular messenger with (ngModelChange), Angular hands you the updated value directly.

So:

  • (change) = "something changed in the element"
  • (ngModelChange) = "here is the new model value"

That is why (ngModelChange) is often easier when using [(ngModel)].

Take Quiz

Syntax and Examples

Recommended syntax: ngModelChange

<select [(ngModel)]="selectedDevice" (ngModelChange)="onChange($event)">
  <option *ngFor="let device of devices" [value]="device">{{ device }}</option>
</select>
selectedDevice = '';
devices = ['Phone', 'Tablet', 'Laptop'];

onChange(newDevice: string) {
  console.log('New selection:', newDevice);
  console.log('Component property:', this.selectedDevice);
}

Why this works

  • [(ngModel)]="selectedDevice" keeps the component property in sync
  • (ngModelChange) passes the new selected value as $event
  • newDevice is the current selection

Using the native change event

If you want to keep (change), read the selected value from the DOM event:

<select [(ngModel)]="selectedDevice" (change)="onChange($event)">
  <option *ngFor="let device of devices" [value]="device">{{ device }}</option>
</select>
onChange(event: Event) {
  const value = (event.target as HTMLSelectElement).value;
  console.log('New selection:', value);
}

Using a template reference variable

Another simple option is to read the select element directly:

<select #deviceSelect [(ngModel)]="selectedDevice" (change)="onChange(deviceSelect.value)">
  <option *ngFor="let device of devices" [value]="device">{{ device }}</option>
</select>
onChange(value: string) {
  console.log('New selection:', value);
}

Important note about *ngFor

Modern Angular syntax uses:

*ngFor="let item of items"

Older examples may show:

*ngFor="#item of items"

The let version is the standard syntax.

Step by Step Execution

Consider this example:

<select [(ngModel)]="selectedDevice" (ngModelChange)="onChange($event)">
  <option *ngFor="let device of devices" [value]="device">{{ device }}</option>
</select>
devices = ['Phone', 'Tablet', 'Laptop'];
selectedDevice = 'Phone';

onChange(newDevice: string) {
  console.log('Selected:', newDevice);
}

What happens step by step

  1. selectedDevice starts as 'Phone'
  2. Angular shows 'Phone' as the selected option
  3. The user changes the selection to 'Laptop'
  4. Angular detects the form control update
  5. ngModel updates selectedDevice to 'Laptop'
  6. (ngModelChange) emits 'Laptop'
  7. onChange('Laptop') runs
  8. The console prints:
Selected: Laptop

Compare that with (change)

If you use:

(change)="onChange($event)"

then onChange() receives a browser event object, not the new model value directly.

You must extract the value yourself:

onChange(event: Event) {
  const value = (event.target as HTMLSelectElement).value;
  console.log(value);
}

Real World Use Cases

This pattern is useful anywhere a dropdown controls app behavior.

Common examples

  • Filtering data
    • Select a category and reload a product list
  • Choosing a device or environment
    • Update a settings panel based on the selected option
  • Sorting results
    • Change from Newest to Price: Low to High
  • Admin dashboards
    • Select a user role, status, or region
  • Forms
    • Choose a country, payment method, or shipping option

Example: filter a list

<select [(ngModel)]="selectedCategory" (ngModelChange)="filterProducts($event)">
  <option *ngFor="let category of categories" [value]="category">{{ category }}</option>
</select>
filterProducts(category: string) {
  console.log('Filter by:', category);
}

The selected value can trigger API calls, local filtering, or UI updates.

Take Quiz

Real Codebase Usage

In real Angular projects, developers usually prefer patterns that make state changes explicit and easy to read.

Common patterns

1. Use ngModelChange when you need the new value immediately

<select [(ngModel)]="status" (ngModelChange)="updateStatus($event)">

This is clear and works well for simple forms.

2. Use guard clauses

If a value is empty or invalid, exit early.

updateStatus(status: string) {
  if (!status) {
    return;
  }

  console.log('Updating status to', status);
}

3. Validate before acting

updateDevice(device: string) {
  if (!this.devices.includes(device)) {
    console.error('Unknown device');
    return;
  }

  this.selectedDevice = device;
}

4. Trigger related updates

A selection often affects more than one thing.

onDeviceChange(device: string) {
  this.selectedDevice = device;
  this.loadDeviceSettings(device);
  this.clearMessages();
}

5. Keep templates simple

Pass the value to the component method and do the logic in TypeScript.

Good:

<select [(ngModel)]="selectedDevice" (ngModelChange)="onDeviceChange($event)">

Avoid putting too much logic in the template.

Why teams prefer this

  • easier to test
  • easier to debug
  • less confusion about event timing
  • better separation between template and logic

Common Mistakes

1. Expecting $event from (change) to be the selected value

Broken assumption:

<select (change)="onChange($event)"></select>
onChange(value: string) {
  console.log(value); // This is not the selected string value
}

$event here is a DOM event object, not the selected option string.

Fix:

onChange(event: Event) {
  const value = (event.target as HTMLSelectElement).value;
  console.log(value);
}

Or use:

(ngModelChange)="onChange($event)"

2. Reading the component property at the wrong time

onChange(event: Event) {
  console.log(this.selectedDevice);
}

This can be confusing when you expect it to always reflect the current DOM change immediately.

Safer approach:

<select [(ngModel)]="selectedDevice" (ngModelChange)="onChange($event)">

3. Omitting [value] on complex options

For simple strings, interpolation may work, but explicitly binding values is clearer.

Better:

<option *ngFor="let device of devices" [value]="device">{{ device }}</option>

4. Using outdated *ngFor syntax

Older syntax:

<option *ngFor="#i of devices">{{ i }}</option>

Current syntax:

<option *ngFor="let i of devices">{{ i }}</option>

5. Confusing change with ngModelChange

They are related, but not the same:

  • change is a native DOM event
  • ngModelChange is an Angular form event that emits the new model value

Comparisons

ApproachWhat it gives youBest use caseExample
(change)DOM event objectWhen you need low-level event details(change)="onChange($event)"
(ngModelChange)New bound valueWhen using [(ngModel)] and you want the updated selection(ngModelChange)="onChange($event)"
Template reference variableDirect element valueSimple templates where you want explicit control(change)="onChange(selectRef.value)"

change vs ngModelChange

FeaturechangengModelChange
SourceBrowser DOM eventAngular forms binding
$event containsEvent objectNew model value
Best forNative event handlingReading updated form values
Works with [(ngModel)]YesYes
Beginner-friendly for formsLessMore

Recommendation

If your goal is simply to get the newly selected value from a dropdown bound with ngModel, prefer ngModelChange.

Take Quiz

Cheat Sheet

<!-- Best choice when using ngModel -->
<select [(ngModel)]="selectedValue" (ngModelChange)="onChange($event)">
  <option *ngFor="let item of items" [value]="item">{{ item }}</option>
</select>
onChange(value: string) {
  console.log(value);
}

Native change event

<select (change)="onChange($event)">
onChange(event: Event) {
  const value = (event.target as HTMLSelectElement).value;
}

Template reference variable

<select #s (change)="onChange(s.value)">

Rules to remember

  • [(ngModel)] = two-way binding
  • (change) = native DOM event
  • (ngModelChange) = new Angular model value
  • Use *ngFor="let item of items"
  • Use [value]="item" for clarity

Common edge case

If options are objects instead of strings, use Angular bindings carefully, often with [ngValue] instead of [value].

FAQ

Why does Angular (change) give me the old value?

Because (change) is a native DOM event, not Angular's model-change event. If you need the new bound value directly, use (ngModelChange).

What is the difference between change and ngModelChange in Angular?

change comes from the browser and gives an event object. ngModelChange comes from Angular forms and gives the new model value.

How do I get the selected option value from a select in Angular?

The simplest way is:

<select [(ngModel)]="selectedValue" (ngModelChange)="onChange($event)">

Can I still use (change) with ngModel?

Yes. You just need to read the value from the event target:

const value = (event.target as HTMLSelectElement).value;

Should I use [value] in Angular option elements?

Yes, it is clearer and more explicit, especially when generating options with *ngFor.

What if my select options are objects, not strings?

Use [ngValue] when binding full objects. [value] converts values to strings.

Is *ngFor="#item of items" still correct?

That is older syntax. In current Angular code, use *ngFor="let item of items".

Take Quiz

Mini Project

Description

Build a small device selector component that lets a user choose a device from a dropdown and immediately displays a message showing the current selection. This demonstrates how to capture the newly selected value correctly in Angular using ngModelChange.

Goal

Create a dropdown that updates the component state and displays the newly selected device as soon as the user changes it.

Requirements

  • Create a list of device names in the component
  • Bind the select element to a component property using ngModel
  • Call a method whenever the selection changes
  • Show the currently selected device below the dropdown
  • Use the newly selected value inside the event handler
Take Quiz

Keep learning

Related questions

View more