Search code examples
angularangular2-forms

No provider for FormGroupDirective in Angular 2 nested custom component


In Angular 2 RC.5 I cannot find a fix for the mentioned error:

Unhandled Promise rejection: Template parse errors:
No provider for FormGroupDirective ("p>Custom begin </p>
      <p>Host contains {{hostFormGroup.directives.length}} directives</p>
      [ERROR ->]<nested></nested>
      <p>Custom end </p>
    </div>
"): CustomComponent@4:6 ; Zone: <root> ; Task: Promise.then ; Value:

happening when a custom component, nested within another custom component, has a dependency on containing @Host() hostFormGroup: FormGroupDirective.

Here's a plunker showing the scenario. AppComponent shows a reactive/model-driven form (temporarily without controls, but that's not crucial at this point) containing CustomComponent, which in turn has a NestedComponent. See developer console for error details.

First-level custom component can have a dependency on hosting FormGroupDirective or not, it does not affect the issue. If it has the dependency, that is resolved correctly. The same does not happen for second-level custom component, no matter what in first-level component.

The problem goes away if the same NestedComponent is used directly in AppComponent.

What am I missing? TA

Here's main part of code, for reference:

import { Component, Host } from '@angular/core';
import {
  REACTIVE_FORM_DIRECTIVES, FormBuilder,
  FormGroup, FormGroupDirective
} from '@angular/forms';

///////////////////////
// Nested

@Component({
  selector: 'nested',
  template: `
    Nested begin<br/>
    Nested end <br/>
  `,
})
class NestedComponent {
  constructor(
    @Host() private hostFormGroup: FormGroupDirective) {
  }
}

///////////////////////
// Custom

@Component({
  selector: 'custom',
  template: `
    Custom begin <br/>
    <nested></nested> <br/>
    Custom end <br/>
  `,
  directives: [NestedComponent],
})
class CustomComponent {
  constructor(
    @Host() private hostFormGroup: FormGroupDirective) {
  }
}

///////////////////////
// App

@Component({
  selector: 'my-app',
  template: `
  <h1>Angular 2 - @Host() issue</h1>
  <form [formGroup]="mainForm" accept-charset="UTF-8" role="form">
    <fieldset>
      <custom></custom>
    </fieldset>
  </form>
  `,
  directives: [REACTIVE_FORM_DIRECTIVES, CustomComponent],
})
export class AppComponent {
  constructor(formBuilder: FormBuilder) {
    this.mainForm = formBuilder.group({});
  }
}

Solution

  • Remove the @Host() decorators and the extra providers and it works.

    @Component({
      selector: 'nested',
      template: `
        <div>
          <p>Nested begin </p>
          <p>Host contains {{hostFormGroup.directives.length}} directives:</p>
          <span *ngFor="let directive of hostFormGroup.directives">{{directive.name}}</span>
          <p>Nested end </p>
        </div>
      `,
      // tried this: no error, but injected one is not the actual container
      // and it containes no directive
      // without it: still same error 'No provider for FormGroupDirective'
      //providers: [FormGroupDirective],
    })
    class NestedComponent {
      constructor(
        private hostFormGroup: FormGroupDirective) {
      }
    }
    // Custom
    
    @Component({
      selector: 'custom',
      template: `
        <div>
          <p>Custom begin </p>
          <p>Host contains {{hostFormGroup.directives.length}} directives:</p>
          <span *ngFor="let directive of hostFormGroup.directives">{{directive.name}}</span>
          <nested></nested>
          <p>Custom end </p>
        </div>
      `,
      directives: [NestedComponent],
      // tried this: still same error 'No provider for FormGroupDirective'
      //providers: [FormGroupDirective],
    })
    class CustomComponent {
      constructor(
        private hostFormGroup: FormGroupDirective) {
      }
    }

    http://plnkr.co/edit/ktvnjm?p=preview