Angular Component 的 metadata 資訊內有兩個可以設定 providers
的地方,分別是 viewProviders
和 providers
,這兩者都可以註冊 providers 但有些微的差異
我們知道 Angular 的 Injection System
,讓 component / service / directive 等可以在 constructor
的地方注入想要使用的服務,根據服務註冊的地方,Angular 會提供一樣或是不一樣的服務實體,到這個地方,是我們所熟知的運作方式
當然我們也可以在 component 註冊服務,已提供本身跟與本身有關的子物件使用,在閱讀 API 文件時,發現 component 有兩個註冊服務的方法,providers
與 viewProviders
這兩者在說明分別為
providers
list of providers available to this component and its childrenviewProviders
list of providers available to this component and its view children
看起來很像,但到底差異在哪裡呢? 主要差異是在於子 component 的呈現方式會因不同註冊服務的方式而有所不同
基本環境設定
來解釋一下,但先準備一下程式環境
1 | // AppComponent 的樣版 |
NgModule.providers
1 | ({ |
在初始狀態, SimpleService
是註冊在 app.module.ts
內,畫面是這樣
不論在左邊或是右邊的 Parent Component 輸入資料時,Child Component 都會顯示所輸入的資料
這時 service 取得的順序
很清楚的,不論是 ParentComponent
或是 ChildComponent
都是存取註冊在 NgModle
的 SimpleService
(圖片擷取至codecraft.tv)
Component.providers
這時當 ParentComponent
註冊 SimpleService
到 providers
內時,會有怎樣的效果呢
1 | import { Component, OnInit } from '@angular/core'; |
執行結果
service 取得的順序
(圖片擷取至codecraft.tv)
在這個情境,不論 ChildComponent
是已哪一種方式顯示在 ParentComponent
都會存取到註冊在 ParentComponent
的 providers,而因為 AppComponent
有兩個 ParentComponent
,所以各自有各自的 SimpleService
互不干擾
Component.viewProviders
如果將 SimpleService
註冊到 viewProviders
時,並子 component 是透過 <ng-content>
映射到 ParentComponent
時
1 | import { Component, OnInit } from '@angular/core'; |
1 | // app-component.html |
執行結果
service 取得的順序
(圖片擷取至codecraft.tv)
viewProviders
比較特殊一點,透過 <ng-content>
呈現與不透過 <ng-content>
的結果不一樣,假設使用 <ng-content>
的方式將 ChildComponent
映射到 ParentComponent
時,兩者所讀取的 SimpleService
會是不同一個 (可參閱上圖);但如果是直接在 ParentComponent
上使用 ChildComponent
時,所存取的 SimpleService
就會跟 ParentComponent
一樣,這部分就要留意了
Recap
component.providers
與 component.viewProviders
最大的差異如上述的實驗,是在 <ng-content></ng-content>
處理的部分,而這裡就是說明時提到的 its view children
的意思了。表示如沒有在 template 上面看到,就不在 viewProviders
的管轄範圍內,可以透過準備好的範例程式,自己動手玩看看,比較有感覺。
Angular 的 DI 機制是很強大的,可以利用這樣的特行來滿足一些特需的效果 (暫時還想不到使用情境),但至少不用因為註冊上的觀念誤解造成找不到資料的窘境出現