我已经在Angular 2中编写了两个服务。其中一个是基本的,自定义的Http
类,其中包含一些自定义功能(它现在看起来很基本,但它会扩展):
ServerComms.ts
import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';
@Injectable()
export class ServerComms {
private url = 'myservice.com/service/';
constructor (public http: Http) {
// do nothing
}
get(options) {
var req = http.get('https://' + options.name + url);
if (options.timout) {
req.timeout(options.timeout);
}
return req;
}
}
另一个类TicketService
使用上面的这个类,并调用服务中的一个方法。这定义如下:
TicketService.ts
import {Injectable} from 'angular2/core';
import {ServerComms} from './ServerComms';
@Injectable()
export class TicketService {
constructor (private serverComms: ServerComms) {
// do nothing
}
getTickets() {
serverComms.get({
name: 'mycompany',
timeout: 15000
})
.subscribe(data => console.log(data));
}
}
但是,每当我尝试这个时,我都会收到以下错误:
"No provider for ServerComms! (App -> TicketService -> ServerComms)"
我不明白为什么?当然,我不需要注入每个其他服务所依赖的每项服务?这会变得相当繁琐吗?这在Angular 1.x中是可以实现的 - 我如何在Angular 2中实现相同的目标?
这是正确的方法吗?
答案 0 :(得分:4)
简而言之,因为注入器是在组件级别定义的,所以启动调用服务的组件必须看到相应的提供者。第一个(直接调用)但另一个间接调用(由前一个服务调用)。
我们来看一个样本。我有以下申请:
组件AppComponent
:在bootstrap
函数中创建Angular2应用程序时提供的应用程序的主要组件
@Component({
selector: 'my-app',
template: `
<child></child>
`,
(...)
directives: [ ChildComponent ]
})
export class AppComponent {
}
组件ChildComponent
:将在AppComponent
组件中使用的子组件
@Component({
selector: 'child',
template: `
{{data | json}}<br/>
<a href="#" (click)="getData()">Get data</a>
`,
(...)
})
export class ChildComponent {
constructor(service1:Service1) {
this.service1 = service1;
}
getData() {
this.data = this.service1.getData();
return false;
}
}
Service1
和Service2
使用Service1
和ChildComponent
Service2
两个服务Service1
@Injectable()
export class Service1 {
constructor(service2:Service2) {
this.service2 = service2;
}
getData() {
return this.service2.getData();
}
}
@Injectable()
export class Service2 {
getData() {
return [
{ message: 'message1' },
{ message: 'message2' }
];
}
}
以下是所有这些元素及其关系的概述:
Application
|
AppComponent
|
ChildComponent
getData() --- Service1 --- Service2
在这种应用中,我们有三个注射器:
bootstrap
函数AppComponent
属性配置的providers
注入器。它可以“看到”应用程序注入器中定义的元素。这意味着如果在此提供程序中找不到提供程序,它将自动查找此父注入程序。如果在后者中找不到,则会抛出“找不到提供者”错误。ChildComponent
注入器遵循与AppComponent
规则相同的规则。要注入为组件执行的注入链中涉及的元素,将首先在此注入器中查找提供者,然后在AppComponent
中查找提供者,最后在应用程序中查找提供者。这意味着当尝试将Service1
注入ChildComponent
构造函数时,Angular2会查看ChildComponent
注入器,然后进入AppComponent
注入器,最后进入申请一。
由于Service2
需要注入Service1
,因此将执行相同的解决方案处理:ChildComponent
注入器,AppComponent
一个和应用程序一。
这意味着可以根据您的需要使用组件的Service1
属性和Service2
函数的第二个参数在每个级别指定providers
和bootstrap
用于应用注射器。
这允许共享一组元素的依赖项实例:
因此它非常强大,您可以根据自己的需要随意组织。
以下是相应的plunkr,您可以使用它:https://plnkr.co/edit/PsySVcX6OKtD3A9TuAEw?p=preview。
Angular2文档中的这个链接可以帮助您:https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html。
答案 1 :(得分:2)
你当然可以。
在Angular2中,有多个注射器。使用providers
组件数组配置注入器。当组件具有providers
数组时,将在树中的该点创建注入器。当组件,指令和服务需要解析它们的依赖关系时,它们会查找注入器树以找到它们。因此,我们需要使用提供程序配置该树。
从概念上讲,我喜欢认为有一个注入树覆盖组件树,但它比组件树更稀疏。
同样,从概念上讲,我们必须配置此注入树,以便在树中的适当位置“提供”依赖关系。 Angular 2不是创建单独的树,而是重用组件树来执行此操作。因此,即使感觉我们在组件树上配置依赖关系,我还是认为我正在配置注入器树上的依赖关系(这恰好覆盖了组件树,因此我必须使用组件来配置它)。 / p>
清除泥土?
Angular 2具有注入器树的原因是允许非单例服务 - 即,能够在注入器树中的不同点处创建特定服务的多个实例。如果您需要类似Angular 1的功能(仅限单例服务),请在根组件中提供所有服务。
构建您的应用,然后返回并配置注入树(使用组件)。这就是我喜欢的方式。如果您在另一个项目中重用组件,则很可能需要更改providers
数组,因为新项目可能需要不同的注入树。
答案 2 :(得分:1)
嗯,我猜你应该全球提供两种服务:
bootstrap(App, [service1, service2]);
或提供给使用它们的组件:
@Component({providers: [service1, service2]})
@Injectable
装饰者添加必要的元数据来跟踪依赖,但不提供它们。