【问题标题】:Angular2 Exception: No provider for ServiceAngular2异常:没有服务提供者
【发布时间】:2016-05-28 19:47:40
【问题描述】:

当我拥有嵌套在根组件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)

我想知道为什么这种行为是非法的。假设我想在我的Child 类中使用GrandChild 类,并在我的App 类中简单地引用Child 类。这似乎是不可能的。

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

非常感谢。

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

【问题讨论】:

    标签: angularjs typescript angular


    【解决方案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() {
      }
    }
    

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

    在您的示例中,您以错误的方式制作东西。如果要从父组件中获取子组件的实例,则需要利用@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();
      }
    
      (...)
    }
    

    您会注意到,当您拥有 @Component 一个时,您不需要 @Injectable 装饰器...

    【讨论】:

      【解决方案2】:

      您可以通过将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

      【讨论】:

      • 我将假设这意味着需要服务实例的最高级别组件必须通过组件元数据将其provide 传递给自身,或者相反必须从父组件继承该服务。这是正确的吗?
      • 你是对的。如果这是你想要做的。
      猜你喜欢
      • 2017-10-08
      • 2017-07-21
      • 2016-02-19
      • 1970-01-01
      • 2017-05-26
      • 2012-07-07
      • 1970-01-01
      • 1970-01-01
      • 2016-12-18
      相关资源
      最近更新 更多