Angular Material Select with Search
October 11, 2019
This page will provide Angular Material Select with search using <mat-autocomplete>
element. The autocomplete is a normal text input with a panel of suggested options. Find the sample code to create select dropdown with search facility.
<mat-form-field> <input type="text" matInput formControlName="profile" [matAutocomplete]="auto"> <mat-autocomplete #auto="matAutocomplete"> <mat-option *ngFor="let pf of allProfiles" [value]="pf">{{pf}}</mat-option> </mat-autocomplete> </mat-form-field>
matInput
attribute and populate the options using <mat-option>
element inside <mat-autocomplete>
element. Then we connect text and options using matAutocomplete
with template reference variable.
To filter the options on writing keyword in text input, we need to write a filter logic according to our requirement. The filtered options are displayed in panel using
valueChanges
of FormControl
.
In the above code snippet, we have a simple array of string in which our value of option and display name both are same. In most of the scenario, we will have an array of objects to be populated in select dropdown in which display value will be a property of object and on selection complete object will be submitted. After selection from drop-down to show selected value a property of that object and not the complete object in text input, we need to use
displayWith
property of <mat-autocomplete>
element to bind a function that will return display value for text input and we will bind complete object to <mat-option>
element so that we can get complete object on selection.
Technologies Used
Find the technologies being used in our example.1. Angular 8.2.8
2. Angular Material 8.2.1
3. Node.js 12.5.0
4. NPM 6.9.0
Complete Example
In our example we have an array ofBook
with some properties.
book.ts
export interface Book { id: number; name: string; writer: string }
import { Injectable } from '@angular/core'; import { of } from 'rxjs'; import { Book } from './book'; const ALL_BOOKS: Book[] = [ { id: 101, name: 'Godaan', writer: 'Premchand' }, { id: 102, name: 'Karmabhoomi', writer: 'Premchand' }, { id: 103, name: 'Pinjar', writer: 'Amrita Pritam' }, { id: 104, name: 'Kore Kagaz', writer: 'Amrita Pritam' }, { id: 105, name: 'Nirmala', writer: 'Premchand' }, { id: 106, name: 'Seva Sadan', writer: 'Premchand' } ]; @Injectable({ providedIn: 'root' }) export class BookService { getAllBooks() { return of(ALL_BOOKS); } saveBook(books) { console.log(JSON.stringify(books)); } }
book.component.html
<h3>Angular Material Select with Search</h3> <form [formGroup]="bookForm" (ngSubmit)="onFormSubmit()" class="book-form"> <mat-form-field class="select-book"> <input type="text" placeholder="Select a book" matInput formControlName="book" [matAutocomplete]="auto"> <mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn"> <mat-option *ngFor="let book of $filteredBooks | async" [value]="book"> {{book.name}} </mat-option> </mat-autocomplete> <mat-error *ngIf="book.hasError('required')"> Book required. </mat-error> </mat-form-field> <br/> <br/> <button mat-raised-button>Submit</button> <button mat-raised-button type="button" (click)="resetForm()">Reset</button> </form>
book.component.ts
import { Component, OnInit } from '@angular/core'; import { FormControl, FormBuilder, Validators } from '@angular/forms'; import { Observable } from 'rxjs'; import { filter, startWith, map, switchMap } from 'rxjs/operators'; import { BookService } from './book.service'; import { Book } from './book'; @Component({ selector: 'app-book', templateUrl: './book.component.html', styleUrls: ['./book.component.css'] }) export class BookComponent implements OnInit { $allBooks: Observable<Book[]>; $filteredBooks: Observable<Book[]>; constructor(private formBuilder: FormBuilder, private bookService: BookService) { } ngOnInit() { this.$allBooks = this.bookService.getAllBooks(); this.$filteredBooks = this.book.valueChanges .pipe( startWith(''), switchMap(value => this.filterBooks(value)) ); } private filterBooks(value: string | Book) { let filterValue = ''; if (value) { filterValue = typeof value === 'string' ? value.toLowerCase() : value.name.toLowerCase(); return this.$allBooks.pipe( map(books => books.filter(book => book.name.toLowerCase().includes(filterValue))) ); } else { return this.$allBooks; } } private displayFn(book?: Book): string | undefined { return book ? book.name : undefined; } bookForm = this.formBuilder.group({ book: [null, Validators.required] }); get book() { return this.bookForm.get('book'); } onFormSubmit() { this.bookService.saveBook(this.bookForm.value); this.resetForm(); } resetForm() { this.bookForm.reset(); } }
book.component.css
.book-form { max-width: 300px; width: 100%; } .select-book { width: 100%; }
import { Component } from '@angular/core'; import { FormControl } from '@angular/forms'; @Component({ selector: 'app-root', template: ` <app-book></app-book> ` }) export class AppComponent { }
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatAutocompleteModule, MatInputModule } from '@angular/material'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { AppComponent } from './app.component'; import { BookComponent } from './book.component'; @NgModule({ declarations: [ AppComponent, BookComponent ], imports: [ BrowserModule, FormsModule, ReactiveFormsModule, BrowserAnimationsModule, MatAutocompleteModule, MatInputModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
Run Application
To run the application, find the steps.1. Install Angular CLI using link.
2. Install Angular Material using link.
3. Download source code using download link given below on this page.
4. Use downloaded src in your Angular CLI application.
5. Run ng serve using command prompt.
6. Access the URL http://localhost:4200
Find the print screen of the output.
