angular: Error: No provider for FormControl

I’m submitting a … (check one with “x”)

[x] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior When my directive constructor injects NgForm, it throws Error: No provider for NgControl!

Expected behavior It’s working when I using Angular 4.0. So my directive can refer to the form control and listen on value changed.

Minimal reproduction of the problem with instructions

here’s my directive:

import {Directive, HostListener, Input, ElementRef, OnInit} from '@angular/core';
import {NgControl} from '@angular/forms';

export class ValidationMessageDirective implements OnInit {

    @Input('validationMessage') customMessage: string;
    constructor(private el: ElementRef, private formControl: NgControl, private validationMessageService: ValidationMessageService) {
        this.target = $(el.nativeElement);
        this.formGroup = this.target.closest('.form-group');

        this.formControl.valueChanges.subscribe((newValue) => {
            this.checkValidation();
        });
    }
}

and my module:

import { NgModule, ModuleWithProviders } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule, FormControlDirective } from '@angular/forms';
import { ValidationMessageDirective } from './src/ng2-validation-message.directive';
import { ValidationMessageService } from './src/ng2-validation-message.service';

export * from './src/ng2-validation-message.directive';
export * from './src/ng2-validation-message.service';

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    ReactiveFormsModule
  ],
  declarations: [
    ValidationMessageDirective
  ],
  exports: [
    ValidationMessageDirective
  ],
})
export class Ng2ValidationMessage {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: Ng2ValidationMessage,
      providers: [ValidationMessageService]
    };
  }
}

What is the motivation / use case for changing the behavior?

Please tell us about your environment: macOS

  • Angular version: 2.0.X

Angular 4.1.x

  • Browser: [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]

all

  • Language: [all | TypeScript X.X | ES6/7 | ES5] TypeScript 2.3.2 ES6

  • Node (for AoT issues): node --version =
    node 6.10

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 17 (5 by maintainers)

Most upvoted comments

@heidermatos and others: If you use angular DI to load NgControl: constructor(private ngControl: NgControl) { } then you cannot declare NG_VALUE_ACCESSOR as a @Component provider at the same time.

Following does not work and leads to Cannot instantiate cyclic dependency! NgControl error:

@Component({
    selector: "my-cmp",
    templateUrl: "mycmp.html",
    providers: [{
        provide: NG_VALUE_ACCESSOR,
        useExisting: MyCmp,
        multi: true
    }]
})
export class MyCmp  implements ControlValueAccessor {
   constructor(private ngControl: NgControl) {
   }

    onButtonClick(): void {
        this.ngControl.reset();
    }

   ... ControlValueAccessor implemented methods, writeValue, registerOnChange etc ...
}

What does work: All you need to do is remove the provider and assign the value accessor manually:

@Component({
    selector: "my-cmp",
    templateUrl: "mycmp.html"
})
export class MyCmp  implements ControlValueAccessor {
   constructor(private ngControl: NgControl) {
        ngControl.valueAccessor = this;
    }

    onButtonClick(): void {
        this.ngControl.reset();
    }

   ... ControlValueAccessor implemented methods, writeValue, registerOnChange etc ...
}

Sorry, I have solved it. This problem happens when the input is not a form control, which is not related to any Angular version.

@crossRT you could share your working code. Thank you.

@heidermatos make sure it’s a form control will solve the problem. what I missed last time is I forget to use ngModel and name attribute for the input