Angular Component 的 metadata 資訊內有兩個可以設定 providers 的地方,分別是 viewProviders 和 providers ,這兩者都可以註冊 providers 但有些微的差異
我們知道 Angular 的 Injection System ,讓 component / service / directive 等可以在 constructor 的地方注入想要使用的服務,根據服務註冊的地方,Angular 會提供一樣或是不一樣的服務實體,到這個地方,是我們所熟知的運作方式
當然我們也可以在 component 註冊服務,已提供本身跟與本身有關的子物件使用,在閱讀 API 文件時,發現 component 有兩個註冊服務的方法,providers 與 viewProviders 這兩者在說明分別為
providerslist of providers available to this component and its childrenviewProviderslist 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 機制是很強大的,可以利用這樣的特行來滿足一些特需的效果 (暫時還想不到使用情境),但至少不用因為註冊上的觀念誤解造成找不到資料的窘境出現