Angular Material Select with Search

By Arvind Rai, 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> 
We can see that we need to create a text using 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 of Book with some properties.
book.ts
export interface Book {
    id: number;
    name: string;
    writer: string
} 
book.service.ts
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));
  }
} 
Find the HTML template.
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> 
Find the component.
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();
  }
} 
Find the other files used in our example.
book.component.css
.book-form {
    max-width: 300px;
    width: 100%;
}
.select-book {
    width: 100%;
} 
app.component.ts
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';

@Component({
  selector: 'app-root',
  template: `
      <app-book></app-book>
  `
})
export class AppComponent {
} 
app.module.ts
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.
Angular Material Select with Search

Reference

Angular Material Autocomplete

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us