Bug/Feature Request
The guide "Creating a custom form field control" should give an example with a custom MatFormFieldControl that implement ControlValueAccessor.
The guide advise us to use:
constructor(..., @Optional() @Self() public ngControl: NgControl) { ... }
But it leads to a cyclic dependancy error:
ERROR Error: Uncaught (in promise): Error: Template parse errors:
Cannot instantiate cyclic dependency! NgControl
Here is a StackBlitz
@angular/material: 2.0.0-beta.12
@angular/core: 4.4.4
@angular/cli: 1.4.4
typescript: 2.4.2
Windows 10 64bit
Chrome/Firefox/Edge
I do not think so.
I find what was wrong: I had to remove the NG_VALUE_ACCESSOR
provider on my custom-input
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CustomInputComponent),
multi: true,
},
Maybe the guide should warn about that.
I have a similar problem. However, removing the NG_VALUE_ACCESSOR
provider yields the following error:
No value accessor for form control with path '...'
I'm trying to implement MatFormFieldControl.errorState
, so I want to derive that from a Validator
that is on the FormControl
.
@GuillaumeNury how did you register your ControlValueAccessor
with Angular?
@ADegele Yes ! I struggled a lot with it !
Here is what I have done:
// Just add this in your constructor
if (this.ngControl) {
this.ngControl.valueAccessor = this;
}
@GuillaumeNury Thank you very much!
Please provide a tutorial of a MatFormFieldControl that implements ControlValueAccessor....
Anyone who has created a custom MatFormFieldControl
with a ControlValueAccessor
want to take a stab at improving the docs?
I did implement a file input that works with MatFormField
and ControlValueAccessor
.
For what it's worth: https://plnkr.co/edit/VGCSprNVT1pobOxjWwmT?p=preview
If i find some time to update the docs, I can give a try.
A cyclic dependency error is also present when providing NG_VALIDATORS
@Component({
...
providers: [
{
provide: MatFormFieldControl,
useExisting: forwardRef(() => MyComponent)
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => MyComponent),
multi: true
}
]
})
export class MyComponent implements MatFormFieldControl<string>, ControlValueAccessor, Validator {
constructor(@Optional() @Self() public ngControl: NgControl) {...}
...
}
Uncaught Error: Template parse errors: Cannot instantiate cyclic dependency! NgControl
I solved the problem by removing Validator
interface from the component and instead provided the validator function directly.
export function phoneNumberValidator(control: AbstractControl) {
...
}
@Component({
selector: 'fe-phone-number-input',
templateUrl: './phone-number-input.component.html',
styleUrls: ['./phone-number-input.component.scss'],
providers: [
{
provide: MatFormFieldControl,
useExisting: forwardRef(() => PhoneNumberInputComponent)
},
{
provide: NG_VALIDATORS,
useValue: phoneNumberValidator,
multi: true
}
]
})
export class MyComponent implements MatFormFieldControl<string>, ControlValueAccessor { ... }
It has any idea to use NG_VALIDATORS in MatFormFieldControl?
I have use @malymato method to implement but some trouble to get component input variable e.g. min or max.
advise for the above comment would be helpful
It's working this way :
you can create method for validation inside your component (or other, if you don't know how look here https://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html#adding-custom-validation):
public validate(c: FormControl): ValidationErrors {
return {
testErr: this.test,
};
}
Then you add it to your NgControl inside AfterViewInit or other method :
if (this._control && this._control.control) {
this._control.control.setValidators(this.validate);
}
Just for info your constructor looks like this :
constructor(
@Self() @Optional() public _control: NgControl,
) {
if (this._control) {
this._control.valueAccessor = this;
}
}
Tell me if stackblitz or plunkr is needed.
Hi everybody,
with the answer of @malymato I got my Control working :-)
Now I try to implement the Validation descripted at the site mentioned by @Maxouhell. But it will not work. I set the validators like described above.
Now I always get the error: this.validateFn is not a function.
On debug I can see, that in the Validation function itself, there is missing the property vaildateFn like descibed in the given link above.
To cut a long story short, could you @Maxouhell plz. make an example on stackblitz?The important thig is, to give an additional value to the Validation function, which is declared as Attribute of the Control.
Best regards
Update:
I fixed my issue. Thx @malymato and @Maxouhell for the important hints and solutions
https://stackblitz.com/edit/angular-fptggt?file=src%2Fapp%2Fstock-counter.component.ts
I just took stock-counter component from ultimate angular tutorial and update it for self validation.
If your counter go > 40 it will be invalid.
Check the code and tell me if you have any questions.
I'm surprised this is still an issue, why have custom field components that cannot be validated without having dig through tickets to actually get them working, why is this not mentioned in the docs.
Could the docs mention how to actually set this up?
Also anyone have any luck getting the fields state setting the UI red?
@crisbeto could you take a look at this one?
Got a full working example in this StackBlitz. This is a custom number input with styled buttons, error state and implements ControlValueAccessor. The SB includes example usage in both Template Driven and Model Driven forms, feel free to link to this in existing or future documentation.
To fix the problem people have been reporting here I had to add a provider for the MatFormFieldControl
to provide my component and set ngControl.valueAccessor = this
in the constructor, as well as a few other changes to support the implementation of ControlValueAccessor
and two way binding
ref #13624
Hey guys,
I had been experiencing a very strange issue while building directive for making input uppercase.
The input was extending DefaultValueAccessor. It was containing an error when having invalid value, but mat-input was not getting red.
The fix appeared to be simple: I was forgetting calling:
this.onTouched() in OnBlur() method.
Hope this helps!
@StickNitro thanks for the StackBlitz, it answered some problems I was having, but I still have one that I can't figure out how to do. When this custom component is in a host form view, and the host view has a Save button, I need the custom component to display the red error validation if it is not in a valid state, such as being empty when it's required. I forked your StackBlitz project to add the Save button to demonstrate what I mean. My StackBlitz fork. Could you update my fork to show how I can accomplish this?
@Maxouhell
I've used your solution for a while, but it's problematic when users of the component want to add other validators that should coexist with the internal validators:
I've fixed the first issue by Validators.compose([this.ngControl.control.validator, ...])
, but I'm yet to find a solution to the second issue.
I'm having the same problem as @kahanu . I need to show the red error validation (mat-form-field-invalid
class) on my custom input field when the value is invalid. I would appreciate any examples showing how to do that.
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._
Most helpful comment
Please provide a tutorial of a MatFormFieldControl that implements ControlValueAccessor....