21
votes

Trying to implement a simple application in angular 2 using angular material.
I implemented a simple table with pagination .

I also used mat-select component, but for this i want implement a search filter to type and search the required option from the list.

Below shown is my .html file

<table>
 <tr><td> Department</td>
<td>
  <mat-form-field>
  <mat-select placeholder=" ">
    <mat-option> </mat-option>
    <mat-option *ngFor="let dep of dept" [value]="dep">{{dep}}</mat-option>
  </mat-select>
</mat-form-field><br/>
</td>
</tr>


</table>

<br><br>

<button >Search</button>

<button >Reset</button>

<button >Close</button>


<mat-card>
<div class="example-container mat-elevation-z8">
  <mat-table #table [dataSource]="dataSource">

    <!-- Account No. Column -->
    <ng-container matColumnDef="accno">
      <mat-header-cell *matHeaderCellDef> Account No. </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.accno}} </mat-cell>
    </ng-container>

    <!-- Account Description Column -->
    <ng-container matColumnDef="accdesc">
      <mat-header-cell *matHeaderCellDef> Account Description </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.accdesc}} </mat-cell>
    </ng-container>

    <!-- Investigator Column -->
    <ng-container matColumnDef="investigator">
      <mat-header-cell *matHeaderCellDef> Investigator </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.investigator}} </mat-cell>
    </ng-container>

    <!-- Account CPC Column -->
    <ng-container matColumnDef="accCPC">
      <mat-header-cell *matHeaderCellDef> Account CPC </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.accCPC}} </mat-cell>
    </ng-container>

     <!-- Location Column -->
    <ng-container matColumnDef="location">
      <mat-header-cell *matHeaderCellDef> Location </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.location}} </mat-cell>
       </ng-container>


 <!-- Client Dept ID Column -->
    <ng-container matColumnDef="cdeptid">
      <mat-header-cell *matHeaderCellDef> ClientDeptID </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.cdeptid}} </mat-cell>
       </ng-container>


        <!-- Dept Description Column -->
    <ng-container matColumnDef="depdesc">
      <mat-header-cell *matHeaderCellDef> Dept Description  </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.depdesc}} </mat-cell>
       </ng-container>


    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
  </mat-table>

  <mat-paginator #paginator
                 [pageSize]="10"
                 [pageSizeOptions]="[5, 10, 20]">
  </mat-paginator>
</div>
</mat-card>

Below shown is my .ts file

import {Component, ViewChild} from '@angular/core';
import {MatPaginator, MatTableDataSource} from '@angular/material';

@Component({
  selector: 'app-account',
  templateUrl: './account.component.html',
  styleUrls: ['./account.component.scss']
})

export class AccountComponent {



  dept = [
    'Administrative Computer',
    'Agosta Laboratory',
    'Allis Laboratory',
    'Bargaman Laboratory',
    'Bio-Imaging Resource Center',
    'Capital Projects',
    'Casanova Laboratory',
    'Darst Laboratory',
    'Darnell James Laboratory',
    'Deans Office',
    'Energy Consultant',
    'Electronic Shop',
    'Facilities Management',
    'Field Laboratory'
  ];


  displayedColumns = ['accno', 'accdesc', 'investigator', 'accCPC','location','cdeptid','depdesc'];
  dataSource = new MatTableDataSource<Element>(ELEMENT_DATA);

  @ViewChild(MatPaginator) paginator: MatPaginator;

   ngAfterViewInit() {
    this.dataSource.paginator = this.paginator;
  }
}

export interface Element {
  accno: number;
  accdesc: string;
  investigator: string;
  accCPC: string;
  location:string;
  cdeptid: number;
  depdesc: string;
}

const ELEMENT_DATA: Element[] = [
  {accno: 5400343, accdesc: 'ASTRALIS LTD', investigator:'Kruger, James G.', accCPC: 'OR',location:'ON',cdeptid: 110350,depdesc: 'Kruger Laboratory'}

  ];

can anybody please help me to implement search filter with mat-select component in my application?

7

7 Answers

21
votes

HTML

<h4>mat-select</h4>
<mat-form-field>
  <mat-label>State</mat-label>
  <mat-select>
     <input (keyup)="onKey($event.target.value)"> // **Send user input to TS**
    <mat-option>None</mat-option>
    <mat-option *ngFor="let state of selectedStates" [value]="state">{{state}}</mat-option>
  </mat-select>
</mat-form-field>

TS

states: string[] = [
    'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware',
    'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky',
    'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi',
    'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico',
    'New York', 'North Carolina', 'North Dakota', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania',
    'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont',
    'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming'
  ];

**// Initially fill the selectedStates so it can be used in the for loop** 
selectedStates = this.states; 

**// Receive user input and send to search method**
onKey(value) { 
this.selectedStates = this.search(value);
}

**// Filter the states list and send back to populate the selectedStates**
search(value: string) { 
  let filter = value.toLowerCase();
  return this.states.filter(option => option.toLowerCase().startsWith(filter));
}

The solution is rather easy. Should work like a charm :)

6
votes

Btw. This might be supported in some of upcoming the Angular Material releases. Discussion is already open: https://github.com/angular/components/issues/5697

4
votes

I found the solution for searching the dropdown values

Here is the html code

<mat-select class="yourClass" [(ngModel)]="searchObj">
            <input class="yourClass" placeholder ="search " (keyup)="onKey($event.target.value)"> 
            <mat-option *ngIf="someCondition" [value]='Select'>Select</mat-option>
            <mat-option *ngFor="let data of dataArray" [value]="data">{{data}}</mat-option>
          </mat-select>

Here is the typescript code key function getting the entered value

    onKey(value) { 
            this.dataArray= []; 
            this.selectSearch(value);       
        }

performing the searching given value inside the provided values in dropdown

selectSearch(value:string){
            let filter = value.toLowerCase();
            for ( let i = 0 ; i < this.meta.data.length; i ++ ) {
                let option = this.meta.data[i];
                if (  option.name.toLowerCase().indexOf(filter) >= 0) {
                    this.dataArray.push( option );
                }
            }
        }

this function is goes where your main search function calling api and getting the data

this.meta.data

        searchDpDropdown(){
            for ( let i = 0 ; i < this.meta.data.length; i ++ ) {
                this.dataArray.push( this.meta.data[i] );
            }
        }
1
votes

I've found out that primefaces for angular does have a multiselect list that allows you to search for listitems. It also includes a builtin select-all button! You can find it here https://www.primefaces.org/primeng/#/multiselect You can install primefaces with npm install primeng --save

-1
votes

I have done some work around for this even though its not correct implementation

component.hml

`

<mat-select formControlName="buyersCountryCode" matInput placeholder="Buyer's Country" required>
                    <input #buyersCountryQuery matInput placeholder="Search"  class="search-input" (keyup)="filterDropDowns(buyersCountryQuery.value, 'BUYERSCOUNTRY')"> 
                    <mat-option *ngFor="let country of filteredBuyersCountry" [value]="country.buyersCountryCode">{{country.buyersCountryValue}}</mat-option>
                </mat-select>

`

component.ts

`

this.filteredBuyersCountry = query
          ? this.filteredBuyersCountry.filter(item =>
              item.buyersCountryValue
                .toLocaleLowerCase()
                .includes(query.toLowerCase())
            )
          : this.dropDowns.buyersCountry;

`

-1
votes
> <mat-form-field>
<mat-label>Items</mat-label>
<mat-select name="item" [(ngModel)]="selected">
  <form>
    <mat-form-field class="w-100">
      <input name="query" type="text" [(ngModel)]="query" matInput>
      <mat-icon matSuffix>search</mat-icon>
    </mat-form-field>
  </form>
  <mat-option>
  </mat-option>
  <mat-option *ngFor="let option of options|appFilter:query" [value]="option">
    {{option.label}}
  </mat-option>
</mat-select>

-1
votes

Instead of customizing the MatSelect in order to add typing search functionality to a list of options, it's optimal to use MatAutocomplete

The autocomplete is a normal text input enhanced by a panel of suggested options.

HTML:

<form class="example-form">
    <input type="text" placeholder="Search for a street" [formControl]="control" 
 [matAutocomplete]="auto">
         <mat-autocomplete #auto="matAutocomplete">
              <mat-option *ngFor="let street of filteredStreets | async" [value]="street">
      {{street}}
             </mat-option>
         </mat-autocomplete>
</form>

TS

control = new FormControl();
  streets: string[] = ['Champs-Élysées', 'Lombard Street', 'Abbey Road', 'Fifth Avenue'];
  filteredStreets: Observable<string[]>;

  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).includes(filterValue));
  }

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

Refferences: Demo (StackBlitz) || Official Docs & Examples