Angular Material Autocomplete Component Force Selection: Complete Example

Angular Material autocomplete component is a text input that shows suggestions while you type. A common validation requirement for an autocomplete control is to force the user to pick an option.

Unfortunately, the autocomplete component does not validate what you type in the input box against the available options.

You have you either click on the option or navigate with arrow keys and press the enter key to make a selection. In most cases though, you want the user to make a selection to validate date entry.

Autocomplete Force Selection

I recently posted a solution in this two year old thread in GitHub that discusses this issue. Several people liked the solution so I want to share it here in my blog.

You can get the full source code from GitHub. Alternatively, run the live demo below.

Custom Validator to Force Selection

Since I was using reactive forms in my project, the easiest way to solve this was to use a custom validator. I have done the following:

Firstly, create a new file requireMatch.ts and add the following function:

import { AbstractControl } from '@angular/forms';

export function RequireMatch(control: AbstractControl) {
    const selection: any = control.value;
    if (typeof selection === 'string') {
        return { incorrect: true };
    }
    return null;
}

This function will evaluate the user input and return a validation error to the form control. Special thanks to Shinigami92 for optimisation.

Import the function into your component and pass it into the form control constructor.

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { Project } from './project';
import { RequireMatch as RequireMatch } from './requireMatch';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  form: FormGroup;
  projects: Project[];

  constructor() {
    this.projects = [
      new Project("Web Development"),
      new Project("UX"),
      new Project("SEO")
    ];
  }

  ngOnInit() {
    this.form = new FormGroup({
      project: new FormControl('', [Validators.required, RequireMatch]),
    });
  }

  displayWith(obj?: any): string | undefined {
    return obj ? obj.name : undefined;
  }
}

Listen to the validation errors on the view like so:

<form [formGroup]="form">
    <mat-form-field class="full-width">
        <input type="text" placeholder="Project" matInput formControlName="project"
 [matAutocomplete]="projectAutoComplete">
        <mat-autocomplete #projectAutoComplete="matAutocomplete" [displayWith]="displayWith">
            <mat-option *ngFor="let project of projects" [value]="project">
                {{ project.name }}
            </mat-option>
        </mat-autocomplete>

        <mat-error *ngIf="form.controls['project'].hasError('required')">
            Please enter a value
        </mat-error>

        <mat-error *ngIf="form.controls['project'].hasError('incorrect')">
            Please select a valid project
        </mat-error>
    </mat-form-field>
</form>

Source code is available on GitHub.

Summary

In this post, I explained how to implement a custom validator to force option selection for Angular Material autocomplete component. This validator basically makes the autocomplete a hybrid between a select and an autocomplete.

Umut Esen

Umut is an enthusiastic software developer, latest web and mobile technology adapter and primary author of onthecode.

Leave a Reply

Close Menu