components
components copied to clipboard
bug(MatFormFieldControl): Custom MatFormFieldControl does not shows errors on form submit unless touched
Reproduction
Steps to reproduce:
- Follow documentation https://material.angular.io/guide/creating-a-custom-form-field-control to create custom MatFormFieldControl with ControlValueAccessor
- Use it in Reactive Form (with some other simple fields)
- Try to save form without touching custom field.
StackBlitz (forked from documentation example with added form element and submit button): stackblitz
Expected Behavior
Form is invalid from the start and on submit all custom MatFormFieldControls are marked as invalid even if not touched.
Actual Behavior
When submitting form all standard fields will be marked as invalid (red) but custom one will not. If you write something into this custom field and then remove this value (making it dirty and touched) then it will correctly be shown as invalid. What is more whole form is VALID if this field is not touched - after you it is dirty then whole form is correctly INVALID.
Environment
- Angular: 12.2.1
- CDK/Material: 12.2.1
- Browser(s): all
- Operating System (e.g. Windows, macOS, Ubuntu): all
Your error state matchers are different.
What you have is
get errorState(): boolean {
return this.ngControl.errors !== null && !!this.ngControl.touched;
}
But Material will check for submitted as well
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
return !!(control && control.invalid && (control.touched || (form && form.submitted)));
}
I assume that guide doesn't have .submitted
as well for simplicity.
@BojanKogoj I updated SB with your code but it changes nothing.
Your CustomStateMatcher isn't being used. Material uses mixinErrorState which calls isErrorState.
I modified your example , changed errorState
get errorState(): boolean {
const parent = this.parentForm || this.parentFormGroup;
return !!this.parts.invalid && (!!this.parts.touched || parent.submitted);
}
And added injected FormGroup and NgForm.
@Optional() private parentForm: NgForm,
@Optional() private parentFormGroup: FormGroupDirective
@BojanKogoj that work with error state which "marks field red". But whole form is still VALID without writing anything into this field.
Same as https://github.com/angular/components/issues/23352 Not sure how to solve this right now.
@marekwalach I'm missing something, maybe it's an emit of the value when the writeValue is started, I believe that implementing ngAfterViewInit with an onChange would solve this problem.
ngAfterViewInit(): void { this.onChange(this.value); }
Can you confirm if it works?
@viniciusschuelter it changes nothing unfortunately.
There are some error triggers that we can't subscribe to (e.g. parent form submissions). so you just have to check for error state update on DoCheck. reference: https://github.com/angular/components/blob/main/src/material/input/input.ts#L350
I will make a PR for it to make the docs more clear.
This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
This action has been performed automatically by a bot.