依赖注入创建多个实例

时间:2017-07-19 19:30:27

标签: angular

我有一个组件可用于向我的应用程序显示一些常见输出。此组件将注入其他服务,以便这些服务可以触发该行为。经过大量的故障排除后,我想我已经将问题跟踪到了Angular的DI,创建了该组件的多个实例。我已经创建了一个简单的版本来说明问题。这是Angular 2.4.x

的AppModule:

import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {HttpModule} from '@angular/http';

import {AppComponent} from './app.component';
import {TestComponent} from "./test.component";

@NgModule({
    declarations: [
        AppComponent,
        TestComponent
    ],
    imports: [BrowserModule, FormsModule, HttpModule],
    providers: [TestComponent],
    bootstrap: [AppComponent]
})
export class AppModule {
}

测试组件(这是我试图用来显示信息并将其用作服务的组件的简化版本):

import {Component, OnInit} from '@angular/core';
@Component({
    selector: 'app-test',
    template: `<p>Message:</p>
    <p *ngIf="show">hi</p>`
})
export class TestComponent {
    private show: boolean = false;
    doTest() {
        setTimeout(() => {
            console.log('timeout callback');
            this.show = true;
        }, 5000);
    }
}

App Component(使用我的测试组件的组件):

import {Component, OnInit} from '@angular/core';
import {TestComponent} from "./test.component";

@Component({
    selector: 'app-root',
    template:`
<h1>{{title}}</h1>
<app-test></app-test>
`
})
export class AppComponent implements OnInit{
    title = 'app works!';
    constructor(private test: TestComponent) { }
    ngOnInit() {
        this.test.doTest();
    }
}

我希望的行为是AppComponent会调用TestComponent的doTest函数,而TestComponent会显示&#39; hi&#39; 5秒钟后发出消息。

回调发生了,我看到了控制台消息,但是&#39; hi&#39;没有显示。我认为依赖注入会提供单独的实例,因此注入App的构造函数的实例与App模板中的实例不同。

如果我的理解是正确的,我如何才能使它在两种情况下都是相同的实例?我是否错过了更好的方法来实现这种行为?

1 个答案:

答案 0 :(得分:1)

您需要使用ViewChild装饰器来访问子组件,而不是将其注入构造函数中。直觉上,你想要做的事情是有道理的,但它不会起作用。

请注意,正如Alexander Staroselsky在评论中指出的那样,您不应该在providers阵列中列出任何组件!

以下是您需要撰写的内容

import { Component, NgModule, ViewChild } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

@Component({
    selector: 'app-test',
    template: `
        <p>Message:</p>
        <p *ngIf="show">hi</p>
    `
})
export class AppTestComponent {
    doTest() {
        setTimeout(() => {
            console.log('timeout callback');
            this.show = true;
        }, 3000);
    }
    show = false;
}

@Component({
    selector: 'my-app',
    template: '<app-test></app-test>',
})
export class App {
    // this queries your view for elements of the type passed to the
    // ViewChild decorator factory.
    @ViewChild(AppTestComponent) test: AppTestComponent;

    ngAfterContentInit() {
        this.test.doTest();
    }
}

@NgModule({
    imports: [BrowserModule],
    declarations: [App, AppTestComponent],
    bootstrap: [App]
})
export class AppModule { }

这是一个工作示例

https://plnkr.co/edit/DDx4INrgixsnJKiU1E0h?p=preview

如果您只使用视图中的子组件,则可以省略所有其他装饰器和生命周期钩子。

例如:

@Component({
    selector: 'my-app',
    template: `
        <!-- give the child component a name for use in the template -->
        <app-test #test>
        </app-test>
        <button (click)="test.doTest()">Do Test</button>
    `,
})
export class App {}

这是一个工作示例

https://plnkr.co/edit/nnXW2z7pbgdTk5Qzl1Sw?p=preview