Angular2异常:没有服务提供者

时间:2016-02-17 08:09:12

标签: angularjs typescript angular

当我拥有嵌套在根组件providing下的组件时,我无法实例化我的应用程序,该组件是它在其构造函数中使用的组件。

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)

我想知道为什么这种行为是非法的。假设我想在我的GrandChild课程中使用Child课程,只需在Child课程中引用App课程。这似乎是不可能的。

创建provide层次结构的正确方法是什么?

非常感谢。

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

2 个答案:

答案 0 :(得分:1)

您可以将父组件直接注入组件,而无需将其指定到组件提供程序中。为此,您需要将组件用于其他组件并将其设置为directives属性:

@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() {
  }
}

您的示例中有点奇怪的是,您没有为组件selectortemplate定义ChildGrandChild属性。它们真的是组件吗?

在你的样本中,你做错了事。如果要从父组件获取子组件的实例,则需要利用@ViewChild装饰器通过注入从父组件引用子组件:

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();
  }
}

这是更新的plunkr:http://plnkr.co/edit/mrVK2j3hJQ04n8vlXLXt?p=preview

您可以注意到也可以使用@Query参数装饰器:

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

  (...)
}

当你拥有@Injectable时,你可能会注意到你不需要@Component装饰者......

答案 1 :(得分:1)

您可以通过向GrandChild的提供商添加App来解决此问题。

但是,当您将它们用作服务时,我不明白为什么您将ChildGrandChild注释为@Component。我想这就是你真正想做的事情。

@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;
    }
}

查看更新的plnkr demo