换句话说,我不想这样做:
export class MyFirstSvc {
}
export class MySecondSvc {
constructor() {
this.helpfulService = new MyFirstSvc();
}
}
export class MyThirdSvc {
constructor() {
this.helpfulService = new MyFirstSvc();
}
}
#1 楼
是的,第一件事是在要注入的每个服务上添加@Injectable
装饰器。实际上,Injectable
名称有点阴险。这并不意味着该类将是“可注入的”,而是将进行修饰,以便可以注入构造函数参数。有关更多详细信息,请参见此github问题:https://github.com/angular/angular/issues/4404。这是我对注入机制的理解。在为类设置
@Injectable
装饰器时,Angular会尝试为当前执行链的注入器中的相应类型创建或获取实例。实际上,不仅有一个用于Angular2应用程序的注射器,而且还有一棵注射器。它们与整个应用程序和组件隐式关联。此级别的一个关键功能是它们以分层方式链接在一起。该注射器树映射组件树。没有为“服务”定义注射器。让我们取样。我有以下应用程序:
组件
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
用于应用程序注入器。这允许共享一组元素的依赖项实例:
如果在应用程序级别定义提供程序,则相应铬被吃的实例将由整个应用程序共享(所有组件,所有服务等)。
如果在组件级别定义提供程序,则实例将由组件本身,其子组件以及所有组件共享依赖项链中涉及的“服务”。
因此它非常强大,您可以根据需要和需要自由进行组织。
这是相应的插件因此您可以使用它:https://plnkr.co/edit/PsySVcX6OKtD3A9TuAEw?p=preview。
Angular2文档中的此链接可以为您提供帮助:https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html。
希望它对您有所帮助(对不起长答案),
蒂埃里
评论
我觉得这是一个很好的答案!我对您说的一句话感到有些困惑:“可注入名称有点阴险。这并不意味着该类将是“可注入的”,而是将进行修饰以便可以注入构造函数参数。” Service1试图注入Service2,因此您需要使用@injectable装饰服务1,以便可以注入您的service2(我从service1中删除了可注入装饰器,因此代码将无法工作)。我对么?我只是想确认一下。谢谢 :-)
–黄Huang
16-3-21在1:46
@GeorgeHuang,是的,如果一个服务依赖于另一个服务,则需要@Injectable()。
– Mark Rajcok
16年4月6日在17:35
@thierry如果我们想在所有其他组件中使用通用组件,我的意思是如何通过整个应用程序为所有其他组件提供通用组件?
–帕迪普·Ja那教
16年4月8日在8:03
@Pardeep您的意思是没有在组件的指令属性中每次都定义?
–Thierry Templier
16年4月8日在8:06
您可以在平台指令中添加它们。参见此链接:github.com/angular/angular/issues/5938。
–Thierry Templier
16年4月8日在8:11
#2 楼
在要使用它们的位置或上方“提供”服务,例如,如果每个服务(子集)只有一个实例,则可以使用
bootstrap()
将它们放在应用程序的根目录。 >在依赖于另一个服务的任何服务上使用@Injectable()
装饰器。将其他服务注入到依赖服务的构造函数中。
import {bootstrap} from 'angular2/platform/browser';
import {AppComponent} from './app.component';
import {MyFirstSvc} from '../services/MyFirstSvc';
import {MySecondSvc} from '../services/MySecondSvc';
bootstrap(AppComponent, [MyFirstSvc, MySecondSvc]);
MySecondSvc.ts
import {Injectable} from 'angular2/core';
import {MyFirstSvc} from '../services/MyFirstSvc';
@Injectable()
export class MySecondSvc {
constructor(private _firstSvc:MyFirstSvc) {}
getValue() {
return this._firstSvc.value;
}
}
其他文件请参见Plunker。
Service DI有点奇怪它仍然取决于组件。例如,
MySecondSvc
是在组件请求时创建的,并且取决于在组件树中“提供” MyFirstSvc
的位置,这可能会影响将哪个MyFirstSvc
实例注入到MySecondSvc
中。这里将详细讨论:您只能通过引导将服务注入服务吗?#3 楼
服务被视为在组件之间共享。因此,假设我有一项服务,则可以在不同的组件中使用它。在这里,我向您展示一种服务,该服务从一个组件接受数据并将该数据发送到其他组件。
我使用了路由,共享-服务,共享对象。
希望这可以帮助您了解共享服务的基本知识。
注意:@Injectable decorater用于使服务可注入。
答案
Boot.ts
import {Component,bind} from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
import {Router,ROUTER_PROVIDERS,RouteConfig, ROUTER_DIRECTIVES,APP_BASE_HREF,LocationStrategy,RouteParams,ROUTER_BINDINGS} from 'angular2/router';
import {SharedService} from 'src/sharedService';
import {ComponentFirst} from 'src/cone';
import {ComponentTwo} from 'src/ctwo';
@Component({
selector: 'my-app',
directives: [ROUTER_DIRECTIVES],
template: `
<h1>
Home
</h1>
<router-outlet></router-outlet>
`,
})
@RouteConfig([
{path:'/component-first', name: 'ComponentFirst', component: ComponentFirst}
{path:'/component-two', name: 'ComponentTwo', component: ComponentTwo}
])
export class AppComponent implements OnInit {
constructor(router:Router)
{
this.router=router;
}
ngOnInit() {
console.log('ngOnInit');
this.router.navigate(['/ComponentFirst']);
}
}
bootstrap(AppComponent, [SharedService,
ROUTER_PROVIDERS,bind(APP_BASE_HREF).toValue(location.pathname)
]);
FirstComponent
import {Component,View,bind} from 'angular2/core';
import {SharedService} from 'src/sharedService';
import {Router,ROUTER_PROVIDERS,RouteConfig, ROUTER_DIRECTIVES,APP_BASE_HREF,LocationStrategy,RouteParams,ROUTER_BINDINGS} from 'angular2/router';
@Component({
//selector: 'f',
template: `
<div><input #myVal type="text" >
<button (click)="send(myVal.value)">Send</button>
`,
})
export class ComponentFirst {
constructor(service:SharedService,router:Router){
this.service=service;
this.router=router;
}
send(str){
console.log(str);
this.service.saveData(str);
console.log('str');
this.router.navigate(['/ComponentTwo']);
}
}
SecondComponent
import {Component,View,bind} from 'angular2/core';
import {SharedService} from 'src/sharedService';
import {Router,ROUTER_PROVIDERS,RouteConfig, ROUTER_DIRECTIVES,APP_BASE_HREF,LocationStrategy,RouteParams,ROUTER_BINDINGS} from 'angular2/router';
@Component({
//selector: 'f',
template: `
<h1>{{myName}}</h1>
<button (click)="back()">Back<button>
`,
})
export class ComponentTwo {
constructor(router:Router,service:SharedService)
{
this.router=router;
this.service=service;
console.log('cone called');
this.myName=service.getData();
}
back()
{
console.log('Back called');
this.router.navigate(['/ComponentFirst']);
}
}
SharedService和共享对象
import {Component, Injectable,Input,Output,EventEmitter} from 'angular2/core'
// Name Service
export interface myData {
name:string;
}
@Injectable()
export class SharedService {
sharingData: myData={name:"nyks"};
saveData(str){
console.log('save data function called' + str + this.sharingData.name);
this.sharingData.name=str;
}
getData:string()
{
console.log('get data function called');
return this.sharingData.name;
}
}
#4 楼
不知道是否仍然需要答案,因此我将继续尝试回答此问题。请考虑以下示例,其中我们有一个使用服务在其模板中填充某些值的组件,如下所示<上面的代码非常简单,它将尝试获取DataService返回的所有getPersons。可以在下面找到DataService文件。
testComponent.component.ts
import { Component } from "@angular/core"
import { DataService } from "./data.service"
@Component({
selector:"test-component",
template:`<ul>
<li *ngFor="let person of persons">{{ person.name }}</li>
</ul>
})
export class TestComponent {
persons:<Array>;
constructor(private _dataService:DataService){
this.persons = this._dataService.getPersons()
}
}
上面的代码无需使用@Injectable装饰器就可以很好地工作。 。但是问题将在我们的服务(在这种情况下为DataService)需要某些依赖(例如)时开始。 Http。如果我们按如下所示更改
data.service.ts
文件,则会收到一条错误消息:data.service.ts
export class DataService {
persons:<Array>;
constructor(){
this.persons = [
{name: "Apoorv"},
{name: "Bryce"},
{name: "Steve"}
]
}
getPersons(){
return this.persons
}
这与Angular 2中的装饰器功能有关。请阅读https: //blog.thoughtram.io/angular/2015/05/03/the-difference-between-annotations-and-decorators.html可以深入了解此问题。
上面的代码也将不起作用,因为我们也必须在引导模块中导入HTTP。
但是我可以建议的一条经验法则是,如果您的服务文件需要依赖项,则应该使用@Injectable装饰器来装饰该类。
参考:https:// blog.thoughtram.io/angular/2015/09/17/resolve-service-dependencies-in-angular-2.html
#5 楼
在连接ComponentA-> ServiceB-> ServiceC时,@ Injectable在Angular 2.0.0-beta.17中不适用于我。我采用了这种方法:
在@ComponentA的providers字段中引用所有服务。
在ServiceB中,使用构造函数中的@Inject注释连接ServiceC。
运行此Plunker来查看示例或查看下面的代码
app.ts
@Component({selector: 'my-app',
template: `Hello! This is my app <br/><br/><overview></overview>`,
directives: [OverviewComponent]
})
class AppComponent {}
bootstrap(AppComponent);
概述.ts
import {Component, bind} from 'angular2/core';
import {OverviewService} from "../services/overview-service";
import {PropertiesService} from "../services/properties-service";
@Component({
selector: 'overview',
template: `Overview listing here!`,
providers:[OverviewService, PropertiesService] // Include BOTH services!
})
export default class OverviewComponent {
private propertiesService : OverviewService;
constructor( overviewService: OverviewService) {
this.propertiesService = overviewService;
overviewService.logHello();
}
}
概述- service.ts
import {PropertiesService} from "./properties-service";
import {Inject} from 'angular2/core';
export class OverviewService {
private propertiesService:PropertiesService;
// Using @Inject in constructor
constructor(@Inject(PropertiesService) propertiesService:PropertiesService){
this.propertiesService = propertiesService;
}
logHello(){
console.log("hello");
this.propertiesService.logHi();
}
}
properties-service.ts
// Using @Injectable here doesn't make a difference
export class PropertiesService {
logHi(){
console.log("hi");
}
}
评论
如果构造函数参数的类型与传递给@Inject(...)的参数相同,并且该类具有@Injectable()(with())注释,则使用@Inject(...)是多余的。
–GünterZöchbauer
16年5月22日在14:49
尝试时,出现“无法解析OverviewService(?)的所有参数”的信息。检查plnkr.co/edit/g924s5KQ0wJW83Qiwu0e?p=preview
–朱利叶斯
16年5月22日在15:31
#6 楼
首先要做的是用@Injectable
注释对所有服务进行注释。请注意注释末尾的括号,没有此解决方案将无法使用。完成此操作后,我们便可以使用构造函数注入将服务相互注入:
@Injectable()
export class MyFirstSvc {
}
@Injectable()
export class MySecondSvc {
constructor(helpfulService: MyFirstSvc) {
}
}
@Injectable()
export class MyThirdSvc {
constructor(helpfulService: MyFirstSvc) {
}
}
#7 楼
首先,您需要提供服务,您可以通过以下引导方法提供服务:
bootstrap(AppComponent,[MyFirstSvc]);
或在应用程序组件上提供,或者在任何其他组件中,取决于您的需求。:
@Component({
...
providers:[MyFirstSvc]
}
...
,然后只需使用构造函数注入服务即可:
export class MySecondSvc {
constructor(private myFirstSvc : MyFirstSvc ){}
}
评论
阅读blog.thoughtram.io/angular/2015/09/17/…此答案可以帮助您注入角度服务