[從 0 開始的 Angular 生活]No.35 了解 @Injectable() 裝飾器與注入 HttpClient 服務元件

前言

之前介紹服務元件的時候就已經看過 @Injectable() 但那個時候並沒有詳加著墨介紹,究竟 @Injectable() 是什麼意思呢?

@Injectable()

Injectable 本身是一個裝飾器 (Decorator) ,主要目的是用於描述這個類別 (class) 是否可以被注入其他的服務元件,事實上如果把之前服務元件上寫的 @Injectable() 刪除,還是可以成功地注入其他元件上,舉例來說:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import { Injectable } from '@angular/core';

export class DataService {
atticleData: Array<any>;
constructor() {
/* tslint:disable */
this.atticleData = [
{
"id": 1,
"href": "http://blog.miniasp.com/post/2016/04/30/Visual-Studio-Code-from-Command-Prompt-notes.aspx",
"title": "從命令提示字元中開啟 Visual Studio Code 如何避免顯示惱人的偵錯訊息",
"date": "2016/04/30 18:05",
"author": "GHJKL",
"category": "Visual Studio",
"category-link": "http://blog.miniasp.com/category/Visual-Studio.aspx",
"summary": "<p>由於我的 Visual Studio Code 大部分時候都是在命令提示字元下啟動,所以只要用 <strong><font color='#ff0000' face='Consolas'>code .</font></strong>就可以快速啟動 Visual Studio Code 並自動開啟目前所在資料夾。不過不知道從哪個版本開始,我在啟動 Visual Studio Code 之後,卻開始在原本所在的命令提示字元視窗中出現一堆惱人的偵錯訊息,本篇文章試圖解析這個現象,並提出解決辦法。</p><p>... <a class='more' href='http://blog.miniasp.com/post/2016/04/30/Visual-Studio-Code-from-Command-Prompt-notes.aspx#continue'>繼續閱讀</a>...</p>"
},
// ... 省略 ...
];
}

doDelete(item){
this.atticleData = this.atticleData.filter(v => v.id !== item.id);
}
doModify(post: any){
this.atticleData = this.atticleData.map((item)=>{
if(post.id === item.id) {
return Object.assign({}, item, post);
}
return item;
});
}
}

刪除 @Injectable() 後功能依然正常,也就是說移除裝飾器後,服務元件依然有被注入成功。

既然可以被移除又何必要寫 @Injectable()

因為它可以注入一些額外其它的服務元件,什麼意思呢?

我們可以透過 @Injectable() 注入 HTTP Client 的元件,從伺服器取得動態的資料。

注入服務元件 HTTP Client

在 Angular 中有內建一個服務元件 HTTP Client ,所以先將其注入目前的 Data Service 中。

Image

  • 值得一提的是這裡的自動完成匯入的路徑並不是我們要的,應修正為:
    • import { HttpClient } from '@angular/common/http';

這才是正確的 HTTP 模組來源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
providedIn: 'root'
})
export class DataService {
atticleData: Array<any>;
constructor(private httpClient: HttpClient) {
/* tslint:disable */
this.atticleData = [
{
"id": 1,
"href": "http://blog.miniasp.com/post/2016/04/30/Visual-Studio-Code-from-Command-Prompt-notes.aspx",
"title": "從命令提示字元中開啟 Visual Studio Code 如何避免顯示惱人的偵錯訊息",
"date": "2016/04/30 18:05",
"author": "GHJKL",
"category": "Visual Studio",
"category-link": "http://blog.miniasp.com/category/Visual-Studio.aspx",
"summary": "<p>由於我的 Visual Studio Code 大部分時候都是在命令提示字元下啟動,所以只要用 <strong><font color='#ff0000' face='Consolas'>code .</font></strong>就可以快速啟動 Visual Studio Code 並自動開啟目前所在資料夾。不過不知道從哪個版本開始,我在啟動 Visual Studio Code 之後,卻開始在原本所在的命令提示字元視窗中出現一堆惱人的偵錯訊息,本篇文章試圖解析這個現象,並提出解決辦法。</p><p>... <a class='more' href='http://blog.miniasp.com/post/2016/04/30/Visual-Studio-Code-from-Command-Prompt-notes.aspx#continue'>繼續閱讀</a>...</p>"
},
// ... 省略 ...
];
}

doDelete(item){
this.atticleData = this.atticleData.filter(v => v.id !== item.id);
}
doModify(post: any){
this.atticleData = this.atticleData.map((item)=>{
if(post.id === item.id) {
return Object.assign({}, item, post);
}
return item;
});
}
}

處理完之後,這個 httpClient 注入還是失敗的,因為還沒將它加入到 ArticleModule 下。

錯誤訊息說明了必須匯入 HttpClientModule 到 ArticleModule

import HttpClientModule

此時網頁又可以正常運作了

前面有提到如果把 @Injectable() 刪除不影響程式運作,但此時如果直接將 @Injectable() 移除可是會出錯的。

意思是無法解析 DataService 內所有的參數,雖然不太懂是什麼意思,但如果看到 resolve 通常是跟相依注入有關。

因為此時相依注入是從建構式內找到一個 httpClient 參數,然後參數標註 HttpClient 型別

  • 所以它必須解析 httpClient 的內容從何而來
    • 此時 Angular 會去找出 HttpClient 並且將其 new 出來成為一個物件實體
      • 再把這個物件實體丟給 httpClient 參數,然後就解析完成 (resolve 就是這個意思)

當透過 Angular CLI 建立服務元件時,預設都會自動加入 @Injectable() ,建議還是不要把它胡亂移除比較好。

於是 HttpClient 服務元件就注入完成了!

如何使用 HttpClient 服務元件

目前文章資料都是寫死的,可以透過 HttpClient 服務元件當中的 get() 方法,動態的取得伺服器上的文章資料。

詳細的 http.get() 方法可以參考官網

而這邊要注意的是 Ajax 的操作在瀏覽器內是非同步的,因此沒辦法在建構式內直接回傳取得的結果

  • 在 Angular 內則是透過 Rxjs 幫忙訂閱 http.get() 資料的結果
    • 而這個 .get() 的資料類型是 Observable 物件 (觀察者物件)
      • 所有的 Observable 物件都必須透過 .subscribe() 方法來訂閱結果
        關於 HttpClient 使用方式可以參考這篇 - HttpClient 功能介紹
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
providedIn: 'root'
})
export class DataService {
atticleData;
constructor(private httpClient: HttpClient) {
httpClient.get('http://localhost:4200/api/articles.json').subscribe((result) => {
console.log(result);
this.atticleData = result;
});
}

doDelete(item) {
this.atticleData = this.atticleData.filter(v => v.id !== item.id);
}
doModify(post: any) {
this.atticleData = this.atticleData.map((item) => {
if (post.id === item.id) {
return Object.assign({}, item, post);
}
return item;
});
}
}

透過 HttpClient 服務元件,正確的接收到資料了!

0%