2017-03-03 37 views
2

我正在處理一個非常大的項目,我們正在儘可能使模塊儘可能模塊化。我們有多個Angular應用程序,並且我們已經創建了一個獨立的通用UI組件庫和一個API工具包,以及這些應用程序中使用的常用服務。將特定服務實例注入到一個父組件的多個實例中

儘管嘗試構建需要使用服務的通用組件,但我們遇到了問題。例如,我現在正在處理一個自動完成組件。該組件應該能夠從遠程源獲取數據,並根據輸入到組件輸入字段中的內容來過濾結果。

該實現對於一個實例來說足夠簡單。我在我的自動完成組件的構造函數中注入了自動完成服務,然後在父進程中提供它。這使我可以靈活地在使用服務時更改爲服務的實現細節,同時仍能創建可與定義的接口一起使用的可重用組件。

例如:

,我們要定義我們的自動完成組件所使用的接口的服務:

@Injectable() 
export class AutocompleteService { 
    public url: string = 'my-api-default'; 

    constructor(http: Http) {} 

    fetch(): any { 
    return this.http.get(this.url); 
    } 
} 

自動完成組件實現:

@Component({ 
    selector: 'my-autocomplete', 
    templateUrl: 'my-autocomplete.component.html' 
}) 
export class MyAutocompleteComponent { 
    constructor(private autocompleteService: AutocompleteService) {} 

    getData() { 
    return this.autocompleteService.fetch(); 
    } 
    ...autocomplete logic... 
} 

現在我可以定義一個承擔實施Autocomplete服務的服務。我可以將熊服務連接到我的自動完成組件,所以我可以選擇我的形式的熊種類。

@Injectable() 
export class BearService { 
    public url: string = 'bear-url'; 

    constructor(http: Http){} 

    fetch() { 
    return this.http.get(this.url); 
    } 
} 

接下來,我定義我的消耗自動完成組件,並提供服務熊讓我的熊種數據父。

@Component({ 
    selector: 'my-form-component', 
    template: ` 
    <form> 
     <my-autocomplete [(ngModel)]="bear"></my-autocomplete> 
     <button type="submit">Submit</button> 
    </form> 
    `, 
    providers: [ 
    {provide: AutocompleteService, useClass: BearService} 
    ] 
}) 
export class MyFormComponent { 
    ...component logic... 
} 

到目前爲止,這麼好。

當我需要構建使用多個自動完成組件的大型表單時,出現了我的問題。我的老闆告訴我,在這張表格上需要三個自動填充字段,一個用於熊類物種,一個用於甜菜物種,另一個用於太空堡壘Gallactica角色。我首先想到的是要做到這一點:

我定義的服務實例:

@Injectable() 
export class BeetsService { 
    public url: string = 'beets-url'; 

    constructor(http: Http){} 

    fetch() { 
    return this.http.get(this.url); 
    } 
} 

@Injectable() 
export class BattleStarGallacticaService { 
    public url: string = 'battlestar-gallactica'; 
    constructor(http: Http){} 

    fetch() { 
    return this.http.get(this.url); 
    } 
} 

然後我更新父模板和供應商:

@Component({ 
    selector: 'my-form-component', 
    template: ` 
    <form> 
     <my-autocomplete [(ngModel)]="bear"></my-autocomplete> 
     <my-autocomplete [(ngModel)]="beet"></my-autocomplete> 
     <my-autocomplete [(ngModel)]="battleStarGallactica"></my-autocomplete> 
     <button type="submit">Submit</button> 
    </form> 
    `, 
    providers: [ 
    {provide: AutocompleteService, useClass: BearService}, 
    {provide: AutocompleteService, useClass: BeetService}, 
    {provide: AutocompleteService, useClass: BattlestarGalacticaService}, 
    ] 
}) 
export class MyFormComponent { 
    ...component logic... 
} 

現在我怎麼能分出哪個自動完成組件使用哪種服務?

我知道我現在有什麼總是使用爲AutocompleteService提供的最後一個提供者,因爲這是Angular DI框架的工作原理。

我也知道我不能使用多供應商,因爲Angular只將它們定義爲NG_VALIDATORSNG_ASYNC_VALIDATORS

那麼,有沒有人有任何想法我可以解決我的問題?我不在乎問題如何得到解決本身,但我仍然需要能夠:

  1. 定義服務接口
  2. 用戶,在可複用組件服務接口
  3. 創建爲我自己的需要實現原始接口的新服務實例
  4. 能夠使用多個組件在一個父組件內使用不同的服務實現實現相同的服務接口

回答

2

我會移動的供應商一個指令,有選擇地加到

@Directive({ 
    selector: 'my-autocomplete[bear]', 
    providers: [{ provide: AutoCompleteService, useClass: BearService}] 
}) 
export class BearDirective {} 

@Directive({ 
    selector: 'my-autocomplete[battlestarGalactica]', 
    providers: [{ provide: AutoCompleteService, useClass: BattlestarGalacticaService}] 
}) 
export class BattelstarGalacticaDirective{} 

,然後使用它像

<form> 
    <my-autocomplete bear [(ngModel)]="bear"></my-autocomplete> 
    <my-autocomplete bear [(ngModel)]="beet"></my-autocomplete> 
    <my-autocomplete battlestarGalactica [(ngModel)]="battleStarGallactica"></my-autocomplete> 
    <button type="submit">Submit</button> 
</form> 

,並從MyFormComponent

+0

感謝這個答案刪除供應商!我要把它付諸實施,它不像我所希望的那樣優雅。現在,使用我們的庫的人有添加步驟創建一個新的指令,並將其添加到模塊,並創建新的服務。我很想看到直接在視圖中註冊提供者的方法 也許將來我們會得到一些很酷的方式來使用多個提供者並直接定義實例在視圖上。我知道我們也有viewProviders,但這種情況有點不同。 –

+1

您需要在構造函數中注入子類('BattlestarGalacticaService'),否則DI現在知道注入的內容。你可以做的是{提供:'AutocompleteService',useValue:{bear:new BearService(),beet:new BeetService(), battlestarGalactica:new BattlestarGalacticaService()}}'然後在組件中添加'constructor(@ Inject('AutoCompleteService')private ac:any){} @Input()type:string;'當你需要訪問你使用'this.ac [type]'的服務' –

+0

那太棒了,完美。非常感謝Günter。 –

相關問題