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