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-error
like:<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
&NgControl
and subscribing tostatusChanges
and 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
errorState
on the custom MatFormFieldControl.Since my custom field is a
formGroup
made of 2 inputs I had to manually set thetouched
I 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 thewrite
method@mxchange What I mean is that the
mat-error
inui-autocomplete.html
will 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
required
validator 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 therequired
validator enabled.