0

i have a question regarding a problem i'm facing so far I've developed a small utility component which works as generic "error display component".


export class ShowErrorComponent {
  // path refering to the form-element
  @Input('path') controlPath = '';
  @Input('name') formName = '';

  constructor(private ngForm: NgForm) {}

  get errorMessages(): string[] | null {
    const form = this.ngForm.form;
    const control = form.get(this.controlPath);
    if (!control || !control.touched || !control.errors) {
      return null;
    }
    return this.getDisplayMessages(control.errors);
  }
  ....
}

I'm using the ShowErrorComponent in two forms. One form is developed with the template driven approach and the other form is developed by the reactive approach. For the template driven approach the errorComponent does the desired job e.g. its printing the error message. However if i'm using the reactive approach my form is not rendered and i'm getting this error message:

ERROR NullInjectorError: R3InjectorError(AppModule)[NgForm -> NgForm -> NgForm]: 
  NullInjectorError: No provider for NgForm!
    at NullInjector.get (core.mjs:6359:27)
    at R3Injector.get (core.mjs:6786:33)
    at R3Injector.get (core.mjs:6786:33)
    at R3Injector.get (core.mjs:6786:33)
    at ChainedInjector.get (core.mjs:13769:36)
    at lookupTokenUsingModuleInjector (core.mjs:3293:39)
    at getOrCreateInjectable (core.mjs:3338:12)
    at Module.ɵɵdirectiveInject (core.mjs:10871:12)
    at NodeInjectorFactory.ShowErrorComponent_Factory [as factory] (show-error.component.ts:9:32)
    at getNodeInjectable (core.mjs:3523:44)

I'm calling the error-component in the following context:

<form
  novalidate
  class="register-form"
  (ngSubmit)="registerMember(registerForm.value)"
  [formGroup]="registerForm"
>
  <div formGroupName="personalInfo">
    <div class="form-group">
      <h3>Personal info:</h3>
      <div class="input-group mb-3">
        <label class="input-group-text" for="gender">Gender</label>
        <select class="form-select" id="membership" formControlName="gender">
          <option value="diverse">Diverse</option>
          <option value="male">Male</option>
          <option value="female">Female</option>
        </select>
      </div>
      <app-show-error name="Gender" path="personalInfo.gender"></app-show-error>
      ...
   </div>
    ...
 </div>
</div>

The registerForm variable refers to my Formgroup and gets initialized inside the constructor and is getting rendered correctly (if is commented out)

Here again the relevant code snippet for the component associated with the preceding html-snippet:

 constructor(fb: FormBuilder) {
    this.registerForm = fb.group({
      personalInfo: fb.group({
        gender: ['diverse'],
        firstname: ['', [Validators.required]],
        lastname: ['', [Validators.required]],
        birthdate: [new Date(), [Validators.required]]
      }),
      ...
    }

I've added the ReactiveFormModule to my Register module. So my question is why does the error occur?

theGoerner
  • 86
  • 1
  • 4

1 Answers1

0

NgForm only exists on template-driven forms, that's why you get the injection error on the reactive example.

To make your error-component work with both form libraries, you could inject ControlContainer instead and from there gain access to the root formDirective. It'd be something like this:

export class ShowErrorComponent {
  ...

  constructor(private controlContainer: ControlContainer) {}

  get errorMessages(): string[] | null {
    const rootDir = this.controlContainer.formDirective as (NgForm|FormGroupDirective)
    const form = rootDir.form;
    const control = form.get(this.controlPath);

    ...
  }
  ...
}

Cheers

akotech
  • 1,961
  • 2
  • 4
  • 10