我有一个Angular2 DI问题。假设我有TestService
,我想在同一个组件中使用此服务的2个不同实例。如果我只是将一个提供程序添加到组件中,并将2个实例添加到构造函数中,那么我最终会使用相同的服务实例。例如:
TestService的
import {Injectable} from "@angular/core";
@Injectable()
export class TestService {
public id: number = Math.random();
public toString(): string {
return "Id: " + this.id;
}
}
测试组件
import {Component, Input, OnInit} from "@angular/core";
import {TestService} from "../../services/test.service";
@Component({
providers: [TestService]
})
export class TestComponent implements OnInit {
constructor(private _testService1: TestService, private _testService2: TestService) { };
ngOnInit() {
console.log("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", this._testService1.toString());
console.log("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", this._testService2.toString());
}
}
控制台中的结果
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Id: 0.24242492129168425
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB Id: 0.24242492129168425
有人可以告诉我是否有方法使用Angular2的DI机制在同一组件中注入多个不同的服务实例,或者我应该删除这个特定案例的DI并创建我的使用手动构造函数手动实例?
提前致谢
答案 0 :(得分:10)
鉴于实例数量有限,直截了当的方式可能是:
@Component({
providers: [
{ provide: 'TestService1', useClass: TestService },
{ provide: 'TestService2', useClass: TestService }
]
})
export class TestComponent implements OnInit {
constructor(
@Inject('TestService1') private _testService1: TestService,
@Inject('TestService2') private _testService2: TestService
) {}
...
}
或OpaqueToken
对应方以避免使用相同的字符串标识符覆盖服务:
export const TestService1 = new OpaqueToken;
export const TestService2 = new OpaqueToken;
...
providers: [
{ provide: TestService1, useClass: TestService },
{ provide: TestService2, useClass: TestService }
]
...
constructor(
@Inject(TestService1) private _testService1: TestService,
@Inject(TestService2) private _testService2: TestService
) {}
它不会伤害TestService
构造函数中的DI。并且TestComponent
的可测试性保持不变,两个服务实例都可以独立模拟。
答案 1 :(得分:4)
每次调用它时,您都可以注入一个返回新实例的工厂:
@NgModule({
providers: [{
provide: 'testService',
useFactory: (/* TestService deps here like `http`*/) =>
(/* params */) => new TestService(/* http */),
deps: [/* TestService deps here like `Http`*/ ]
}]
})
@Component(...)
export class TestComponent implements OnInit {
constructor(@Inject('testService') private _testServiceFactory) { };
ngOnInit() {
console.log("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", this._testServiceFactory( /* params */).toString());
console.log("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", this._testServiceFactory().toString());
}
}
Plunker example (单击按钮时检查浏览器控制台中的输出)
答案 2 :(得分:2)
我会创建一个静态方法,在服务中返回新实例,并在组件中只通过DI注入一个。类似的东西:
import {Injectable} from "@angular/core";
@Injectable()
export class TestService {
public id: number = Math.random();
public toString(): string {
return "Id: " + this.id;
}
static init() {
return new TestService();
}
}
然后在组件中:
import {Component, Input, OnInit} from "@angular/core";
import {TestService} from "../../services/test.service";
@Component({
providers: [TestService]
})
export class TestComponent implements OnInit {
_testService1: TestService;
_testService2: TestService;
constructor(_testFactory: TestService) {
this._testService1 = _testFactory.init();
this._testService2 = _testFactory.init();
};
ngOnInit() {
console.log("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", this._testService1.toString());
console.log("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", this._testService2.toString());
}
}