Angular Material: How to validate Autocomplete against suggested options?
There are two scenarios with Angular Material Autocomplete that may need to be validated against a list of selected options:
- Array of strings - Suggested options are defined in an array of strings
- Array of Objects - Suggested options are an object property defined on an array of Objects (In this scenario,
displayWith
Input would be used.)
** Stackblitz Demo **
Validate Options from Array of strings
To validate autocomplete
against an array of string options, the validator may accept the array of options and check if the control value is included.
function autocompleteStringValidator(validOptions: Array<string>): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
if (validOptions.indexOf(control.value) !== -1) {
return null /* valid option selected */
}
return { 'invalidAutocompleteString': { value: control.value } }
}
}
The validator could be added to a FormControl
along with other built-in validators such as Validators.required
:
public autocompleteControl = new FormControl('',
{ validators: [autocompleteStringValidator(this.options), Validators.required] })
Validate Options from Array of Objects
To validate autocomplete
against an array of object options, the validator can leverage the fact that the control.value
will only be a string
if a valid Object
option has not been selected.
function autocompleteObjectValidator(): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
if (typeof control.value === 'string') {
return { 'invalidAutocompleteObject': { value: control.value } }
}
return null /* valid option selected */
}
}
For those who may need a similar approach. Here's my solution. I've built a custom validation rule according to my needs.
SELECTBOX_VALUE: [
null,
Validators.compose([
Validators.required,
FormCustomValidators.valueSelected(this.myArray),
]),
];
export class FormCustomValidators {
static valueSelected(myArray: any[]): ValidatorFn {
return (c: AbstractControl): { [key: string]: boolean } | null => {
let selectboxValue = c.value;
let pickedOrNot = myArray.filter(
(alias) => alias.name === selectboxValue
);
if (pickedOrNot.length > 0) {
// everything's fine. return no error. therefore it's null.
return null;
} else {
//there's no matching selectboxvalue selected. so return match error.
return { match: true };
}
};
}
}