我知道如何将服务注入组件(通过@Component),但是如何使用DI在组件之外传递服务呢?

换句话说,我不想这样做:

export class MyFirstSvc {

}

export class MySecondSvc {
    constructor() {
        this.helpfulService = new MyFirstSvc();
    }
}

export class MyThirdSvc {
    constructor() {
        this.helpfulService = new MyFirstSvc();
    }
}


评论

阅读blog.thoughtram.io/angular/2015/09/17/…

此答案可以帮助您注入角度服务

#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; 
  }
}



两个Service1Service2服务:Service1ChildComponentService2使用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函数的第二个参数在每个级别上指定providersbootstrap用于应用程序注入器。

这允许共享一组元素的依赖项实例:


如果在应用程序级别定义提供程序,则相应铬被吃的实例将由整个应用程序共享(所有组件,所有服务等)。
如果在组件级别定义提供程序,则实例将由组件本身,其子组件以及所有组件共享依赖项链中涉及的“服务”。

因此它非常强大,您可以根据需要和需要自由进行组织。

这是相应的插件因此您可以使用它: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 ){}
}