简体   繁体   中英

Angular2 Exception: No provider for Service

I'm unable to instantiate my application when I have the component which is nested under the root component providing a component which it uses in it's constructor.

import {Component, Injectable} from 'angular2/core';


@Component()
export class GrandChild(){
  constructor () {
    this.hello = "hey!"
  }
}

@Component({
  providers: [GrandChild]
})
@Injectable()
export class Child {
    constructor(public grandchild: GrandChild) {
        this.grandchild = grandchild;
    }
}

@Component({
    providers: [Child],
    template: `Everything rendered fine!`,
    selector: 'app'
})

export class App {
    kid: Child;

    constructor(public child: Child) {
        this.kid = child;
    }
}

EXCEPTION: No provider for GrandChild! (App -> Child -> GrandChild)

I'm wondering why this behavior is illegal. Let's say I wanted to use the GrandChild class in my Child class and simply reference the Child class in my App class. This seems to be impossible.

What is the correct way to create the provide hierarchy?

Thanks a bunch.

PLNKR: http://plnkr.co/edit/5Z0QMAEyZNUAotZ6r7Yi?p=preview

You can inject directly the parent component into a component without specifying it into component providers. To do that you need to use component into other ones and set it into the directives attribute:

@Component({
  selector: 'child',
  template: `
    <div></div>
  `
})
export class Child {
  constructor(@Inject(forwardRef(() => App)) parent: App) {
  }
}

@Component({
  directives: [Child],
  template: `
    Everything rendered fine!
    <child></child>
  `,
  selector: 'app'
})
export class App {
  constructor() {
  }
}

What is a bit strange in your sample is that you didn't define selector and template properties for components Child and GrandChild . Are they really components?

In your sample, you made things in the wrong way. If you want to get instances of child component from a parent component, you need to leverage the @ViewChild decorator to reference the child component from the parent one by injection:

import { Component, ViewChild } from 'angular2/core';  

(...)

@Component({
  selector: 'my-app',
  template: `
    <h1>My First Angular 2 App</h1>
    <child></child>
    <button (click)="submit()">Submit</button>
  `,
  directives:[App]
})
export class AppComponent { 
  @ViewChild(SearchBar) searchBar:SearchBar;

  (...)

  someOtherMethod() {
    this.searchBar.someMethod();
  }
}

Here is the updated plunkr: http://plnkr.co/edit/mrVK2j3hJQ04n8vlXLXt?p=preview .

You can notice that the @Query parameter decorator could also be used:

export class AppComponent { 
  constructor(@Query(SearchBar) children:QueryList<SearchBar>) {
    this.childcmp = children.first();
  }

  (...)
}

You can notice that you don't need the @Injectable decorator when you have the @Component one...

You can fix it by adding GrandChild to App 's providers.

However, I don't understand why you were annotating Child and GrandChild as @Component when you're using them as services. I guess this is what you actually wanted to do.

@Injectable()
export class GrandChild(){
  constructor () {
    this.hello = "hey!"
  }
}

@Injectable()
export class Child {
    tire: string;
    constructor(public grandchild: GrandChild) {
        this.grandchild = grandchild;
    }
}

@Component({
    providers: [Child, GrandChild],
    template: `Everything rendered fine!`,
    selector: 'app'
})
export class App {
    thread: Thread;
    selected: boolean = false;
    kid: Child;

    constructor(public child: Child) {
        this.kid = child;
    }
}

See updated plnkr demo .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM