Reputation: 1515
I have an Angular Material Autocomplete drop-down with a filter that filters by CustomerName
.
This was implemented via my returned Customers from my getAllCustomers()
method. I then do a loop
through each Customer
to push
the CustomerName
into a new array
, which essentially becomes my filteredOptions
.
My question is: How can I implement this filter with the search on the CustomerName, but have a binding to the Id of each Customer?
In the object
that I eventually want to save, I want to save the Customer.Id
and not the CustomerName
.
I have tried creating a new object array
, containing both the CustomerName
and Id
, but this does not work with the filteredOptions
and filter
method. It seems like the filter
method only takes an array
with single values and not objects
.
Also, I would need to bind this correctly in my HTML
.
Here is my basic fileredOptions
implementation: (Note: I included my object
{name: element.CustomerName, id: element.Id}
that I wish to use. This doesn't work as explained. The working method simply pushes element.CustomerName
into the array
:
filteredOptions: Observable<string[]>;
constructor(private loadDataService: LoadDataService, private assetDataService: AssetDataService, private router: Router, private toastr: ToastrService) { }
ngOnInit() {
this.getAllCustomers();
}
filter(val: string): string[] {
return this.customerNameArray.filter(option => option.toLowerCase().indexOf(val.toLowerCase()) === 0);
}
getAllCustomers() {
this.loadDataService.getAllCustomers()
.subscribe(data => {
this.customerArray = data;
let thisArray = [];
this.customerArray.forEach(element => {
thisArray.push({name: element.CustomerName, id: element.Id});
});
this.customerNameArray = thisArray;
this.filteredOptions = this.myCustomerSearchControl.valueChanges.pipe(
startWith(''),
map(val => this.filter(val))
);
});
}
Here is my HTML
:
<mat-form-field>
<input type="text" placeholder="Customer Search" aria-label="Number" matInput [formControl]="myCustomerSearchControl" [matAutocomplete]="auto">
<mat-autocomplete autoActiveFirstOption #auto="matAutocomplete">
<mat-option *ngFor="let option of filteredOptions | async" [value]="option">
{{ option }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
Upvotes: 9
Views: 3711
Reputation: 17918
If you use an object for your options, you will need to modify your filter function and filteredOptions to use the object and not a string array. You will also need to use the displayWith feature of mat-autocomplete to allow the input to work with the object. A stackblitz example is here.
Your code:
export class Customer{
constructor(public CustomerName: string, public Id: number) { }
}
...
filteredOptions: Observable<Customer[]>;
constructor(private loadDataService: LoadDataService, private assetDataService: AssetDataService, private router: Router, private toastr: ToastrService) { }
ngOnInit() {
this.getAllCustomers();
}
filter(val: any) {
let name = val.CustomerName || val; // val can be Customer or string
return this.customerNameArray.filter(option => option.CustomerName.toLowerCase().indexOf(name.toLowerCase()) === 0);
}
getAllCustomers() {
this.loadDataService.getAllCustomers()
.subscribe(data => {
this.customerArray = data;
let thisArray = [];
this.customerArray.forEach(element => {
thisArray.push(new Customer(element.CustomerName, element.Id));
});
this.customerNameArray = thisArray;
this.filteredOptions = this.myCustomerSearchControl.valueChanges.pipe(
startWith(null),
map(val => this.filter(val))
);
});
}
displayCustomer(cust: Customer) {
return cust ? cust.CustomerName : '';
}
HTML:
<mat-form-field>
<input type="text" placeholder="Customer Search" aria-label="Number" matInput [formControl]="myCustomerSearchControl" [matAutocomplete]="auto">
<mat-autocomplete autoActiveFirstOption #auto="matAutocomplete" [displayWith]="displayCustomer">
<mat-option *ngFor="let option of filteredOptions | async" [value]="option">
{{ option.CustomerName }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
Upvotes: 4