Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How bind to an Id in an Angular Material Autocomplete drop-down, but filter by the string representation

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>
like image 928
onmyway Avatar asked Mar 08 '18 09:03

onmyway


People also ask

How do you clear mat autocomplete when no option is selected from autocomplete dropdown?

Answers 1 : of How to clear mat- autocomplete when no option is selected from autocomplete dropdown. You can remove the formControl-binding from your input and when you select an option you set that id to your form.

How do I use angular material autocomplete?

Simple autocompleteStart by creating the autocomplete panel and the options displayed inside it. Each option should be defined by a mat-option tag. Set each option's value property to whatever you'd like the value of the text input to be when that option is selected.

What is Matautocomplete in angular?

The <mat-autocomplete>, an Angular Directive, is used as a special input control with an inbuilt dropdown to show all possible matches to a custom query. This control acts as a real-time suggestion box as soon as the user types in the input area.

Can't bind to Matautocomplete since it isn't a known property of input angular?

If 'mat-option' is an Angular component and it has 'value' input, then verify that it is part of this module. If 'mat-option' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule. schemas' of this component to suppress this message.


1 Answers

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>
like image 65
G. Tranter Avatar answered Oct 28 '22 16:10

G. Tranter