How to get Id of selected value in Mat-Select Option in Angular 5

The question is specific to Angular 5 but for others coming here with a newer version of Angular, the (change) event won't work for mat-select.

In Angular 6 the (change) event has been changed to (selectionChange).

So it would be:

<mat-form-field>
    <mat-select placeholder="Client*" #clientValue  (selectionChange)="changeClient($event.value)">
    <mat-option  *ngFor="let client of clientDetails" [value]="client.id">
      {{client.clientName}}
    </mat-option>
  </mat-select>
</mat-form-field>

And in the component:

changeClient(value) {
    console.log(value);
}

From this answer and the documentation.


Component => app.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { MaterialDropDown, PAYMENT_MODES } from './order.model';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})

export class AppComponent implements OnInit {
  name = 'Angular';
  sampleForm: FormGroup;
  paymentModes: MaterialDropDown[];
  constructor() {}

  ngOnInit() {
    this.paymentModes = PAYMENT_MODES;
    this.sampleForm = new FormGroup({
      payment_mode: new FormControl(null, Validators.required),
    });
  }

  get f() {
    return this.sampleForm.controls;
  }

  onPaymentSelection() {
    console.log(this.sampleForm.value.payment_mode);
  }

  onSubmit() {
    console.log(this.sampleForm.value);
  }
}

Module => app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatSelectModule } from '@angular/material/select';
import { MatButtonModule } from '@angular/material/button';
@NgModule({
  imports: [ 
    BrowserModule, 
    BrowserAnimationsModule,
    FormsModule, 
    ReactiveFormsModule, 
    MatFormFieldModule, 
    MatSelectModule,
    MatButtonModule
    ],
  declarations: [ AppComponent, HelloComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

Model => order.model.ts

export interface MaterialDropDown {
    value: string;
    viewValue: string;
}

export const PAYMENT_MODES: MaterialDropDown[] = [
    { value: 'Cash', viewValue: 'Cash' },
    { value: 'cheque', viewValue: 'Cheque' },
    { value: 'dd', viewValue: 'Demand Draft' },
    { value: 'neft', viewValue: 'NEFT' },
    { value: 'rtgs', viewValue: 'RTGS' },
    { value: 'upi', viewValue: 'UPI' }
];

View => app.component.html

<form [formGroup]="sampleForm" (ngSubmit)="onSubmit()">
    <mat-form-field>
        <mat-label>Payment Mode</mat-label>
        <mat-select formControlName="payment_mode" (ngModelChange)="onPaymentSelection($event)">
            <mat-option *ngFor="let payment_mode of paymentModes" [value]="payment_mode.value">
                {{ payment_mode.viewValue }}
            </mat-option>
        </mat-select>
        <mat-hint *ngIf="!f.touched">Please select a valid Payment Mode.</mat-hint>
        <div *ngIf="!f.payment_mode.valid && f.payment_mode.touched">
            <mat-error *ngIf="f.payment_mode.errors.required">Payment Mode field is required</mat-error>
        </div>
    </mat-form-field>
  <button type="submit" mat-raised-button color="primary" [disabled]="sampleForm.invalid">Save</button>
</form>
<p style="color: #f00">Check Console for outputs</p>

CSS => app.component.css

mat-form-field { width: 280px; margin-right: 35px}

WORKING DEMO


For that you need to :

Change (change)="changeClient($event)" to (change)="changeClient($event.value)"

and from [value]="client.clientName" to [value]="client.id"

<mat-form-field>
    <mat-select placeholder="Client*" #clientValue  (change)="changeClient($event.value)">
    <mat-option  *ngFor="let client of clientDetails"   [value]="client.id">
      {{client.clientName}}
    </mat-option>
  </mat-select>
</mat-form-field>

WORKING DEMO


You can also subscribe to the values change of the mat-select by using the ViewChild decorator and ngAfterViewInit which is less 'html-intrusive'.

Here is an example :

[HTML]

<mat-form-field [floatLabel]="auto">
    <mat-label>Type</mat-label>
        <mat-select #matSelect required> //the #matSelect is important here
            <mat-option *ngFor="let type of types" [value]="type.value">
                {{type.viewValue}}
            </mat-option>
    </mat-select>
</mat-form-field>

[TS]

 import { Component, ViewChild, AfterViewInit } from '@angular/core';
 import { MatSelect } from '@angular/material';

 @Component({
        selector: 'app-export-security-pack-material',
        templateUrl: './export-security-pack-material.component.html',
        styleUrls: ['./export-security-pack-material.component.scss']
 })

 export class ExportSecurityPackMaterialComponent implements AfterViewInit {

    constructor() {}

    types: Object[] = [
        { value: 'example-value-0', viewValue: 'ExampleViewValue0' 
        },
        { value: 'example-value-1', viewValue: 'ExampleViewValue1' }
    ];

    @ViewChild('matSelect') matSelect: MatSelect;
       //Reference Variable //variable Name //Type

    ngAfterViewInit() {
        this.matSelect.valueChange.subscribe(value => {
            console.log(value);
        });
    }
 }

With this your value should be logged in the development console Ctrl+Shift+I or F12 everytime you change your selector value.

or you can literally just do this if you dont need onchange :

[HTML]

<mat-form-field [floatLabel]="auto">
    <mat-label>Type</mat-label>
        <mat-select [(value)]="matSelectValue" required> <---
            <mat-option *ngFor="let type of types" [value]="type.value">
                {{type.viewValue}}
            </mat-option>
    </mat-select>
</mat-form-field>