21

My requirement was to show the selected value in the Input Box and get the Selected Id and Value to the .ts file. As I need the Id and Value I am binding the option value directly to [value]. But if I do that it's getting printed as [Object Object].

<mat-form-field appearance="outline" class="w-100">
            <mat-label>Enter Hotel Name</mat-label>
            <input type="text" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto">
            <mat-autocomplete #auto="matAutocomplete" (optionSelected)="selectedclient($event)">
                <mat-option *ngFor="let option of clients; let i = index" [value]="option">
                    {{ option.name }}
                  </mat-option>
            </mat-autocomplete>
            <mat-icon matSuffix>location_on</mat-icon>
          </mat-form-field>

Ts File

    options = [
        { id: 1, name: 'One'},
        { id: 2, name: 'Two'},
        { id: 3, name: 'Three'}
       ];

selectedclient(event) {
     console.log(event.option.value);
   }

Stackblitz Editor URL: https://stackblitz.com/edit/angular-mat-select-data-n4tvmj

Gvs Akhil
  • 2,165
  • 2
  • 16
  • 33

1 Answers1

52

You want to make use of the displayWith attribute. Per the manual:

If you want the option's control value (what is saved in the form) to be different than the option's display value (what is displayed in the text field), you'll need to set the displayWith property on your autocomplete element. A common use case for this might be if you want to save your data as an object, but display just one of the option's string properties.

To make this work, create a function on your component class that maps the control value to the desired display value. Then bind it to the autocomplete's displayWith property.

Template side

<mat-autocomplete ... [displayWith]="getOptionText">

Script side

getOptionText(option) {
  return option.name;
}

Demo: https://stackblitz.com/edit/angular-mat-select-data-cddqia

Jeto
  • 14,596
  • 2
  • 32
  • 46
  • 2
    Its working as expected but I am getting this error. ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'name' of null TypeError: Cannot read property 'name' of null at MatAutocomplete.push../src/app/pages/hotels/homepage/homepage.component.ts.HomepageComponent.getOptionText [as displayWith] (homepage.component.ts:49) at MatAutocompleteTrigger.push../node_modules/@angular/material/esm5/autocomplete.es5.js.MatAutocompleteTrigger._setTriggerValue (autocomplete.es5.js:925) at autocomplete.es5.js:628 – Gvs Akhil Mar 11 '19 at 10:00
  • 1
    @GvsAkhil There must be a case where your option is null, you can check the value within `getOptionText` with something like `return option ? option.name : null;` (replace `null` with anything more appropriate if need be). – Jeto Mar 11 '19 at 10:03
  • Ya Its working thanks a lot but one doubt we are not passing any parameter in [displayWith]="getOptionText" but its returning the correct name. How is it possible? – Gvs Akhil Mar 11 '19 at 10:07
  • 2
    @GvsAkhil This simply holds a reference to a function, Angular will automatically pass whatever you set as `[value]` as its argument. – Jeto Mar 11 '19 at 10:13
  • Okk thanks a lot I am struggling with it from past one hour – Gvs Akhil Mar 11 '19 at 10:15
  • What if this works on one page and shows `[Object Object]` anyway on another one? Option has been chosen correctly, `[displayWith]="myFunc"` where `myFunc()` does not get called at all. – Evgeny Nozdrev Dec 07 '19 at 13:00
  • 1
    The function gets call a LOT even with Angular's OnPush change detection strategy. – Russ May 11 '20 at 23:56
  • It works with Angular 12, thanks! – Carnaru Valentin Nov 03 '21 at 07:02