Injecting ngControl in custom validator directive, causes cyclic dependency
Asked Answered
W

3

25

i'm trying to create custom angular 2 validator directive, which inject NgControl like this :

@Directive({
  selector: '[ngModel][customValidator]',
  providers: [{provide: NG_VALIDATORS, useExisting: CustomValidatorDirective, multi: true}]
})
export class CustomValidatorDirective implements Validator {
  private validateFunction: ValidatorFn;

  constructor(private control: NgControl) { };

}

But i get the following error:

Cannot instantiate cyclic dependency! NgControl

Does anyone know how i can workarround it, so i can access the ngControl after intialization?

Warlike answered 1/10, 2016 at 16:42 Comment(4)
which version are you using?Helfrich
The version is 2.0.0Warlike
can you remove providers section from here and add it into @NgModel({})?Helfrich
Thanks @Helfrich , looks like this solved the problem.Warlike
H
6

Providers, Pipes, Directives declaration are removed from @Component or @Directive decorators after RC6 or RC7. So you just need to remove

providers: [{provide: NG_VALIDATORS, useExisting: CustomValidatorDirective, multi: true}] 

from directive

and add it into @NgModule({}) decorator

@NgModule({
 ...
 providers: [{provide: NG_VALIDATORS, useExisting: CustomValidatorDirective, multi: true}]

})
Helfrich answered 1/10, 2016 at 19:15 Comment(3)
AFAIK providers property on a directive still works. It was not removed github.com/angular/angular/blob/master/modules/%40angular/core/… angular.io/docs/ts/latest/cookbook/…Flood
@Flood Thanks for the share. Then problem could be not to provide such provider configuration here. Or may be providing providers here may create other instance or something.Helfrich
I think putting the provider registration in the NgModule rather than the Directive will cause the validator to be shared across the modules which can access the CustomValidatorDirective. Obviously it will pollute NG_VALIDATORS when other directives also use it.Colecolectomy
W
26

You can inject NgControl via Injector to avoid cyclic dependency.

constructor(private _injector: Injector) { }

ngOnInit() {
  console.log(this._injector.get(NgControl))
}
Woof answered 11/1, 2018 at 11:5 Comment(1)
It seems that injector.get(NgControl) is depreciated. See this for an alternative solution.Thumbprint
H
6

Providers, Pipes, Directives declaration are removed from @Component or @Directive decorators after RC6 or RC7. So you just need to remove

providers: [{provide: NG_VALIDATORS, useExisting: CustomValidatorDirective, multi: true}] 

from directive

and add it into @NgModule({}) decorator

@NgModule({
 ...
 providers: [{provide: NG_VALIDATORS, useExisting: CustomValidatorDirective, multi: true}]

})
Helfrich answered 1/10, 2016 at 19:15 Comment(3)
AFAIK providers property on a directive still works. It was not removed github.com/angular/angular/blob/master/modules/%40angular/core/… angular.io/docs/ts/latest/cookbook/…Flood
@Flood Thanks for the share. Then problem could be not to provide such provider configuration here. Or may be providing providers here may create other instance or something.Helfrich
I think putting the provider registration in the NgModule rather than the Directive will cause the validator to be shared across the modules which can access the CustomValidatorDirective. Obviously it will pollute NG_VALIDATORS when other directives also use it.Colecolectomy
Z
0

Just remove the NG_VALIDATORS from the providers of the @Directive

providers: [{provide: NG_VALIDATORS, useExisting: CustomValidatorDirective, multi: true}] 

and set the component's validator on the constructor

constructor(public ngControl: NgControl) {
  ngControl.valueAccessor = this;
}
Zolnay answered 1/8 at 11:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.