How to make a Material custom form field control (like this one) to support form validation and display them with mat-error? I understand that the regular matInput directive uses ErrorStateMatcher (doc) but I don't understand how I can link it with a custom form field.
-
1I've had the same issue (not yet solved). I've also created a ticket as a hope for someone can update the docs. https://github.com/angular/material2/issues/13624 – Michael Oct 16 '18 at 06:06
4 Answers
By looking at some existing component from Material2 (https://github.com/angular/components/blob/master/src/material/select/select.ts), I found a solution. I created a base class following this example
export const _MatSelectMixinBase:
CanDisableCtor &
HasTabIndexCtor &
CanDisableRippleCtor &
CanUpdateErrorStateCtor &
typeof MatSelectBase =
mixinDisableRipple(mixinTabIndex(mixinDisabled(mixinErrorState(MatSelectBase))));
I had to copy from the Material repo some types like CanUpdateErrorStateCtor.
Then update my constructor to inject a ErrorStateMatcher and finally in ngDoCheck, do this:
ngDoCheck() {
if (this.ngControl) {
this.updateErrorState();
}
}

- 889
- 1
- 8
- 12
-
Spent the whole day solving this issue! Can't thank you enough! – Server Khalilov Aug 02 '19 at 15:44
-
@Rémi, the link leads to a 404 page. Also I cannot import `MatSelectBase` from anywhere. Maybe it's a private class now? – Tsvetan Ganev Sep 16 '19 at 13:24
-
@TsvetanGanev it looks like the new link is this one https://github.com/angular/components/blob/master/src/material/select/select.ts. – Rémi Sep 17 '19 at 14:20
-
MatSelectBase is a private class that you will have to copy. Search for _MatSelectMixinBase in the select.ts file. – Rémi Sep 17 '19 at 14:22
-
Thanks. In the end I just copy-pasted Google's code into my own component. Dirty solution but it's the only one I found. – Tsvetan Ganev Sep 17 '19 at 14:26
If you followed the official guide to create a custom material form field,
and you have declared ngControl
in constructor:
constructor(
...,
@Optional() @Self() public ngControl: NgControl) {
...
if (this.ngControl != null) {
this.ngControl.valueAccessor = this;
}
}
all you need is:
get errorState(): boolean {
return this.ngControl.invalid && this.ngControl.dirty;
}
to get validation working.

- 1,248
- 14
- 9
you can check that from the FocusMonitor
in the example
,it can be something like this:
fm.monitor(elRef.nativeElement, true).subscribe(origin => {
if (this.parts.status === 'INVALID') {
this.errorState = true;
}
this.focused = !!origin;
this.stateChanges.next();
});
the idea is material provide errorState
, you can see that from the component's type, so whenever you change it, it will reflect on the component, hope it's help!

- 215
- 1
- 13
The solution is correct! Reusing of mixinErrorState from material core is the best way to handle it. I recently released a detailed video about custom form field where also gave detailed explanation to error handling in custom form fields. It might be interesting for others who understands better by watching video https://youtu.be/AZsw2nRxkBk?t=825

- 265
- 2
- 11