components: Strange mat-error & state behaviour on Custom ControlValueAccessor component
Bug
I have this custom input component, using ControlValueAccessor and it is perfectly in sync with the controlling formGroup, and gives the valid, invalid, touched and hasErrors('required') to the formGroup & internally correctly.
What is the current behavior?
Whenever i want to use the mat-error component, it will only work as expected when I give the required attribute to the input. When I leave that out, the mat-error will never show, whatever I try. So on blur (touched=true) it will not show the mat-error. But it does in this simple plunkr: https://plnkr.co/edit/cJFCUITMlcBc78v06937?p=preview
I’m not sure why this is, the only thing I can think of is that I use [(ngModel)]="_value" on the input i.c.w. NG_VALUE_ACCESSOR/ControlValueAccessor, but I would think that since the formGroup state is correct, and it all works perfectly when having the required property on it, this should be irrelevant.
Looking at this @crisbeto’s answer: https://github.com/angular/material2/issues/4027 Point 1 seems to be saying a similar thing, that setting required on it, it works, and towards the end @willshowell states Errors are hidden until the input is both invalid and touched yet they are both invalid and when touched still don’t show it.
What is the expected behavior?
I would expect the required to not be relevant to showing the mat-error element. For example, I might want to validate an email with Validators.email but have it optional.
What are the steps to reproduce?
This plunkr demonstrates it by simply clicking and blurring each input field: https://plnkr.co/edit/4B2OOc5Spv9ewxbeIndZ?p=preview
Although While recreating it in plunkr, I found out some new strange behaviour. The first instance of the component doesn’t seem to apply the placeholder attribute, and also doesn’t change the touched state; however this problem has not occurred on my project (yet). See: https://plnkr.co/edit/FODeH4ZhE7IG01dmYCiR?p=preview This does indicate something strange going on, and I cannot figure out what it is.
What is the use-case or motivation for changing an existing behavior?
I would expect required not to be required for mat-error to work.
Which versions of Angular, Material, OS, TypeScript, browsers are affected?
- “@angular/material”: “2.0.0-beta.11”,
- “@angular/common”: “^4.3.6”,
- “@angular/compiler”: “^4.3.6”,
- “@angular/compiler-cli”: “^4.3.6”,
- “@angular/core”: “^4.3.6”,
- “@angular/forms”: “^4.3.6”,
- “@angular/http”: “^4.3.6”,
- “typescript”: “^2.4.2”,
Is there anything else we should know?
- I’ve spent hours trying to fix this and trying to figure out why this happens. I’m pretty convinced it is a problem with the implementation of
mat-error. - I’ve tried transcluding the
mat-errorlike:<mat-error error>{{ getError() }}</mat-error>and then<ng-content select="[error]"></ng-content>But then it is placed wrongly and will always show the error, probably would not fix this issue either. - I’ve tried accessing the state internally on the component, with
Injector&NgControland subscribing tostatusChangesand could see the internal status is correct as well.
About this issue
- Original URL
- State: open
- Created 7 years ago
- Reactions: 2
- Comments: 18 (4 by maintainers)
I solved by updating the
errorStateon the custom MatFormFieldControl.Since my custom field is a
formGroupmade of 2 inputs I had to manually set thetouchedI call this function when either input is focused
EDIT
There was also a problem with the reset and errors won’t be reset. To solve, call
yourFormControlOrGroup.reset()as first in thewritemethod@mxchange What I mean is that the
mat-errorinui-autocomplete.htmlwill respond only to the validity of the search input (the one it is a sibling of in amat-form-field). It is bound to this element and not to your outer component. Thus it will only show when the search input has an error. The search input only has an error when empty if it is marked asrequired.The “works without required” example you provided actually does have the
requiredvalidator active, but it is active in the controller rather than the template because it is an example of reactive rather than template-driven forms. Note theformControlName="email"in the template which links the input toemail: ['', [Validators.required] ]in the controller, which had therequiredvalidator enabled.