Angular 服務與依賴注入
今天在解掉了工作上遇到的問題後,也順便加深了對 Angular 的瞭解,主要是在 Service 以及 Dependency injection 的處理應用上。
雖然官方文件上都寫得清清楚楚,不過當初上手開發的時候,只有買一個線上課程,花一個週末的時間上完課就硬上了,不然公司有任務要做,沒有太多時間讓我慢慢熟悉這個新的前端開發框架,所以在同事的推薦下,花了一些錢買了 Udemy 上的課程 「Angular 開發實戰:從零開始」,這是業界有名的保哥開的課程,很快的讓我就能夠上手,剩下的就是參考目前專案內其他類似的程式碼了。
而這次遇到的問題,再花了很久時間 debug 後發現是使用到的某個服務,在某些情況下會保留前一次某列表的搜尋參數資料,然後在下次到另一個列表時,會再把先前的參數帶入,造成不必要的 filter,而 query 不出原本預期的結果。一開始先使用 workaround 的方式在每次要進行 query 前,重新把不必要的參數清空,確實可以解決問題,但是這樣無法滿足人類想探求真理的心。
因為這種會多帶參數的情況,在某頁面的五個 tab 下,有三個頁面的列表會出現這情況,另外兩個則不會。所以就根據這樣的線索來找差異性。後來發現似乎在 @Component
裡面,兩者差了一個 providers
,在試著把有問題的三個列表用同樣的方式加上 providers
就可以解決問題。
所以底下就來介紹一下 Service 以及 Dependency injection 的關聯。
官方文件:服務與依賴注入簡介
開發 Service 註冊與使用方式
在 Angular 下,如果要將一個 Class 撰寫成可以被重複使用的 Service,那就在撰寫的時候,將這個 Class 上方加入 @Injectable()
這個裝飾器,然後在特定的 NgModule 內註冊使用,這樣就可以在其他 Component 中透過在 constructor
內加入這 Service 就能夠注入使用。
// hero.service.ts |
({ |
// hero-list.component.ts |
這種寫法,會讓 Server 在還沒初始化時,新增一個 instance 後回傳給 component 來使用。如果已經初始化過了,就會回傳已經存在的 instance。所以當不同 Component 都使用這樣的方式來注入 Service 時,就會用到 Service 內相同的 heros 屬性。
// if heroService is not existed, it will new an instance of HeroService |
每個 Component 使用新的 Service instance
如果在不同的 Component 中,要注入一個新的 Service 的 instance,就要在 @Component()
裡面使用 providers
屬性來註冊 Service,這時候就會替這個 Component 產生一個新的 Service instance。
// hero-list.component.ts |
建立 Singleton Service
另外,如果 Service 需要使用到 Singelton 模式,就是在 @Injectable()
裡面加入 providedIn: 'root'
,這樣就會在 App Module 中生成一個 Singelton instance,並且在其他 Component 中也可以直接使用。
// hero.service.ts |
至於如果已經在 @Injectable
裡面加上 providedIn: 'root'
,而在 Component 使用時,又用上 providers
屬性,我目前還沒這樣做過,不過我猜 Singleton 應該就失效了,畢竟強迫要新增一個 instance 了。