2016-04-15 93 views
0

我已經在Angular 2中編寫了兩個服務。其中一個是基本的定製類Http,它具有一些自定義功能(現在看起來很基本,但它將會擴展):Angular 2 - 服務 - 從另一個服務的依賴注入

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中實現同樣的效果?

這是正確的做法嗎?

回答

4

簡而言之,由於噴射器是在組件級定義的,因此發起呼叫服務的組件必須看到相應的提供者。第一個(直接調用),另一個間接調用(由前一個服務調用)。

讓我們來看一個例子。我有以下應用:

  • 組件AppComponent:子組件將:那就是在bootstrap功能

    @Component({ 
        selector: 'my-app', 
        template: ` 
         <child></child> 
        `, 
        (...) 
        directives: [ ChildComponent ] 
    }) 
    export class AppComponent { 
    } 
    
  • 組件ChildComponent創建Angular2應用程序時提供了我的應用程序的主要成分用於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; 
        } 
    } 
    
  • 個兩個服務,Service1Service2Service1使用由ChildComponentService2通過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一個應用程序之一。

這意味着兩個Service1Service2可以在每一級根據使用providers屬性組件和所述bootstrap功能的應用程序噴射器的第二參數您的需要來指定。

這使得共享依賴的情況下,一組元素:

  • 如果您在應用程序級別定義提供商,把對應的創建的實例將通過整個應用程序中共享(所有組件,所有服務,...)。
  • 如果您在組件級別定義提供程序,則實例將由組件本身,其子組件以及依賴鏈中涉及的所有「服務」共享。

因此,它非常強大,您可以根據自己的需要自由組織。

這是相應的plunkr,所以你可以玩它:https://plnkr.co/edit/PsySVcX6OKtD3A9TuAEw?p=preview

Angular2文檔中的這個鏈接可以幫助您:https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html

2

你當然可以。

在Angular2中,有多個注射器。噴油器使用providers組件陣列進行配置。當某個組件具有providers數組時,將在該樹中的該點處創建一個注入器。當組件,指令和服務需要解析它們的依賴關係時,它們會查找注入器樹來查找它們。所以,我們需要使用提供者來配置那棵樹。

概念上,我喜歡認爲有一個覆蓋組件樹的注入器樹,但它比組件樹更稀疏。

同樣,在概念上,我們必須配置此注入器樹,以便在樹的適當位置「提供」依賴關係。 Angular 2不是創建一個單獨的樹,而是重新使用組件樹來執行此操作。因此,儘管感覺就像我們在組件樹上配置依賴關係一樣,但我喜歡認爲我正在配置注入器樹上的依賴關係(正好覆蓋組件樹,所以我必須使用組件來配置它)。

清澈如泥?

Angular two具有注入樹的原因是爲了允許非單實例服務–,即能夠在注入樹中的不同點創建特定服務的多個實例。如果您需要Angular 1類功能(只有單件服務),請在您的根組件中提供所有服務。


建築師您的應用程序,然後回去(使用組件)配置噴油器樹。我就是這麼想的。如果您在其他項目中重新使用組件,極有可能需要更改providers陣列,因爲新項目可能需要不同的注入器樹。

1

好吧,我想你應該在全球範圍提供兩種服務:

bootstrap(App, [service1, service2]); 

或提供使用它們的組件:

@Component({providers: [service1, service2]}) 

@Injectable裝飾增加了跟蹤依賴條件所需的元數據,但不提供他們。