Search code examples
angularangular-forms

What is the best way to access fromControl within a custom form control


Inside one of my custom form controls I need to access its formcontrol. It turns out that this is not very straight forward. On the internet I found 3 solutions:

  1. Use the validator interface and access the control as followsd

    public validate(c: FormControl) {
       if (!this.control)
       this.control=c;
       return c?.errors;
    }
    
  2. Use inject or the Injector which (in my case) always give a Circular dependency injection error or No provider for NgControl

     this.ngControl = inject(NgControl);
    

or

this.ngControl = this.injector.get(NgControl);
  1. Access the FormControl using @Input

     @Input() formControl: FormControl;
    

This one doesn't work with formControlName unfortunately.

So the question is, based on my findings, that I should use 1) or 3). Or is there an other solution?


Solution

  • As I wrote you can get it from FormControlName directive applied to your host element.

    Keep in mind that this is a circular dependency injection therfore you have to access it in post constuction phase - in my example, it is ngAfterViewInit callback

    In your custom form control

         constructor(@Optional() @Host() private injector: Injector) {
          
          }
          ngAfterViewInit() {
            // setTimeout(() => {
              const formControlName = this.injector.get(FormControlName);
              console.log('ctrl??', formControlName.control);
            //
    
     });
      }
    

    which results in

    ctrl?? FormControl{validator: ƒ, asyncValidator: null, _onCollectionChange: ƒ, pristine: true, …}

    I have forked some random stackblitz example to POC it out.

    https://stackblitz.com/edit/custom-form-control-angular-kaoexe?file=src%2Fapp%2Fprovince-select%2Fprovince-select.component.ts%3AL49,src%2Fapp%2Fprovince-select%2Fprovince-select.component.html

    Ignore errors as those are for other 2 controls that uses ngModel and `formControl instead

    on the other hand, this is actually the same what you have already tried, it just bypassing circular dependency injection problem thus you can adopt your solution the same way