在Angular中使用依賴注入(DI)的時候,咱們通常會使用providers
。其實要作一樣的事咱們還有另一個選擇:viewProviders
。
viewProviders
容許咱們定義只對組件的view可見的provider。下面咱們用例子詳細的說明這一點。
假設咱們有一個簡單的服務:ide
// myService.service.ts import { Injectable } from '@angular/core'; @Injectable() export class MyService{ testIfGetService(where){ console.log('Got My Service in ' + where); } }
這個服務很簡單,只須要打印出在哪裏調用了該服務。
而後有一個子組件,是用來投射到父組件裏面的(等會將會看到):this
// child.component.ts import { Component } from '@angular/core'; import { MyService } from './myService.service'; @Component({ selector: 'vp-child', template: ` <div>This is child!!!</div> ` }) export class VPChild{ constructor( private service: MyService ){ this.service.testIfGetService('child'); } }
這個組件注入了MyService
服務,調用MyService
的testIfGetService
方法,並傳入child
代表這是在child組件調用的。
還有另一個子組件,這個組件是用來放在父組件的模板(template)裏面的:google
// viewChild.component.ts import { Component } from '@angular/core'; import { MyService } from './myService.service'; @Component({ selector: 'vp-viewchild', template: ` <div>This is viewChild!!!</div> ` }) export class ViewVPChild{ constructor( private service: MyService ){ this.service.testIfGetService('viewChild'); } }
這裏一樣注入MyService
服務,調用MyService
服務的testIfGetService
方法,並傳入viewChild
。
最後是父組件:code
// parent.component.ts import { Component } from '@angular/core'; import { MyService } from './myService.service'; @Component({ selector: 'vp-parent', template: ` <div>This is parent!!!</div> <ng-content></ng-content> <vp-viewchild></vp-viewchild> `, providers: [MyService] }) export class VPParent{ constructor( private service: MyService ){ this.service.testIfGetService('parent'); } }
在父組件,用providers
註冊MyService
,而後調用MyService
的testIfGetService
傳入parent
。
而後就像這樣使用父組件:component
<vp-parent> <vp-child></vp-child> </vp-parent>
運行程序,控制檯打印出告終果:
blog
一切就像預期那樣!!
而後,咱們用viewProviders
代替providers
註冊MyService
,看看會發生什麼:console
// parent.component.ts import { Component } from '@angular/core'; import { MyService } from './myService.service'; @Component({ selector: 'vp-parent', template: ` <div>This is parent!!!</div> <ng-content></ng-content> <vp-viewchild></vp-viewchild> `, viewProviders: [MyService] // <--- }) export class VPParent{ constructor( private service: MyService ){ this.service.testIfGetService('parent'); } }
這樣修改以後,運行程序,發現報錯了:
table
若是把contentChild註釋掉,就像這樣:模板
<vp-parent> <!-- <vp-child></vp-child> --> </vp-parent>
是不會報錯的:
class
這就說明,在父組件用viewProviders
註冊的provider,對contentChildren是不可見的。而使用providers
註冊的provider,對viewChildren和contentChildren均可見!
補充說明:組件會逐級向上尋找provider,直到找到爲止,不然就會拋出錯誤。就像這裏:
<vp-parent> <vp-child></vp-child> </vp-parent>
vp-child
往上找MyService
的provider,結果在vp-parent
找到了。可是在用viewProviders
的時候,vp-child
往上找,也就是到vp-parent
,結果沒找到,而後又去找vp-parent
的父級,仍是沒找到(由於在這個例子裏,咱們只在vp-parent
註冊了MyService
),而後又繼續往上找……如此找到邊界也沒找到,因此拋出了一個錯誤。若是你不但願這樣,可使用@Host
作出限制,就像這樣:
constructor( @Host() private service: MyService ){}
關於@Host()本文不做展開,有興趣能夠自行google。