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>
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, '');
}
}