Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular 依赖注入创建多个实例_Angular - Fatal编程技术网

Angular 依赖注入创建多个实例

Angular 依赖注入创建多个实例,angular,Angular,我有一个组件,用于显示应用程序的一些常见输出。该组件被注入到其他服务中,以便这些服务可以触发该行为。经过大量的故障排除,我想我已经跟踪到Angular的DI创建组件的多个实例的问题。我已经创建了一个简单的版本来说明这个问题。这是角度2.4.x 应用模块: import {BrowserModule} from '@angular/platform-browser'; import {NgModule} from '@angular/core'; import {FormsModule} from

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

应用模块:

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);
    }
}
使用我的测试组件的应用程序组件:

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会在5秒钟后显示“hi”消息

回调发生了,我看到了控制台消息,但没有显示“hi”。我认为依赖项注入提供了独立的实例,所以注入应用程序构造函数的实例与应用程序模板中的实例不同

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

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

请注意,正如Alexander Staroselsky在他的评论中指出的,您不应该在提供者数组中列出任何组件

这是你需要写的

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 { }
下面是一个工作示例

如果您仅使用视图中的子组件,那么可以省去所有额外的装饰器和生命周期挂钩

例如:

@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 {}
下面是一个工作示例


要获取对测试组件的引用,可以在AppComponent的模板中使用,也可以使用ViewChild装饰器。将其注入构造函数是不正确的,但考虑这样做是合理的。TestComponent或任何其他组件不应在provider属性中声明为提供程序。一般来说,你只会把类装饰成@Injectable,通常是服务。我本来打算有一个单独的服务,但我在别处读到另一篇堆栈溢出文章,我认为该组件扩展了Injectable,因此,任何标记为组件的内容都可以被视为可注入的内容,无论这样做是否明智……@AlexanderStaroselsky您绝对正确,组件不应添加到提供程序数组,但这与可注入装饰器工厂无关。@AluanHaddad您绝对正确。我同意您利用ViewChild解决此问题的方法。我发表评论的目的是促进有关供应商的更好实践。谢谢谢谢我认为这解决了我的问题,正如我在上面所说明的,但我认为在尝试创建一个简单的问题版本,而不是发布实际的代码片段时,我稍微歪曲了我的问题。组件A有我的TestComponent,但它是第三个调用TestComponent的doTest方法的服务,称为服务B。我认为我可能应该这样做:创建一个服务,让我的测试组件侦听来自该服务的事件。然后,其他服务可以调用将触发新事件的方法。可能会详细说明问题或提出新问题。出于好奇,中介的其他选项是什么?您可以使用应用程序中某个ECMAScript模块导出的普通旧共享对象或函数OK,但并不理想。如果要缓存,可以使用全局变量,也可以使用本地存储及其本机事件。也就是说,服务是你在这里的最佳选择,但我想指出的是,角度的方式不是唯一的方式。谢谢。来自Java,以及在这种背景下的各种选择,最近做Angular是一种有趣的经历。始终感谢您了解所有可用选项。