mat-auto complete show name but send value

77 views Asked by At

An auto-complete select that show a list of options. Each option is an object. I want to show the name of each option but send it's Id. This code works. But once the option is selected, the input shows the id. I want to show the name.

Documentation suggests the use of [displayWith]="displayFn" but it require to change [value]="freespin.id" by [value]="freespin" and I don't want that.

I have not found a solution yet.

                  <mat-form-field>
                    <mat-label>Freespin</mat-label>
                    <input type="text"
                           placeholder="Select a freespin"
                           matInput
                           formControlName="freespin"
                           [matAutocomplete]="auto">
                    <mat-autocomplete requireSelection #auto="matAutocomplete">
                        <mat-option *ngFor="let freespin of filteredFreespins[i] | async" [value]="freespin.id">
                            {{freespin.name}}
                        </mat-option>
                    </mat-autocomplete>
                </mat-form-field>
1

There are 1 answers

0
Naren Murali On BEST ANSWER

Could you try using the displayWith attribute, please find below a working example!

html

<form class="example-form">
  <input
    type="text"
    placeholder="Search for a street"
    [formControl]="control"
    [matAutocomplete]="auto"
    class="example-input"
  />
  <mat-autocomplete
    #auto="matAutocomplete"
    [displayWith]="displayWith.bind(this)"
  >
    @for (street of filteredStreets | async; track street) {
    <mat-option [value]="street.id">{{street.name}}</mat-option>
    }
  </mat-autocomplete>
</form>

ts

import { Component, OnInit } from '@angular/core';
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { Observable } from 'rxjs';
import { startWith, map } from 'rxjs/operators';
import { AsyncPipe } from '@angular/common';
import { MatAutocompleteModule } from '@angular/material/autocomplete';

/**
 * @title Plain input autocomplete
 */
@Component({
  selector: 'autocomplete-plain-input-example',
  templateUrl: 'autocomplete-plain-input-example.html',
  styleUrls: ['autocomplete-plain-input-example.css'],
  standalone: true,
  imports: [FormsModule, MatAutocompleteModule, ReactiveFormsModule, AsyncPipe],
})
export class AutocompletePlainInputExample implements OnInit {
  control = new FormControl('');
  streets: any[] = [
    { id: 1, name: 'Champs-Élysées' },
    { id: 2, name: 'Lombard Street' },
    { id: 3, name: 'Abbey Road' },
    { id: 4, name: 'Fifth Avenue' },
  ];
  filteredStreets: Observable<any[]>;

  ngOnInit() {
    this.filteredStreets = this.control.valueChanges.pipe(
      startWith(''),
      map((value) => this._filter(value || ''))
    );
  }

  private _filter(value: string): string[] {
    const filterValue = this._normalizeValue(value);
    return this.streets.filter((street) =>
      this._normalizeValue(street.name).includes(filterValue)
    );
  }

  displayWith(val: any) {
    if (val) {
      const found = this.streets.find((x: any) => x.id === val);
      return found && found.name ? found.name : val;
    } else {
      return val;
    }
  }

  private _normalizeValue(value: string): string {
    return value.toLowerCase().replace(/\s/g, '');
  }
}

stackblitz