iT邦幫忙

2021 iThome 鐵人賽

DAY 3
0
Modern Web

關於我作夢變成工程師這檔事(Angular 篇)系列 第 3

第 3 天 「速速前呂布奉先!」|NgModule、HttpClientModule、新增元件

  • 分享至 

  • xImage
  •  

前情提要

在昨天我們建立了 Angular 專案、使用 JSON-server 來製作 mock db,並且建立了英雄資料。今天這篇文章我們將完成下列事項:

  • 使用 HttpClientModule 來取得英雄資料。
  • 新增 HeroListComponent 元件。

005

(現在,我們要試著召喚英靈...)

我知道!再怎麼說,我也是個讀書人呢。

(哦?你知道什麼?)

要召喚英靈對吧,那就要唸這個咒文——「速速前呂布奉先!」。

(呃...)

我知道問題出在哪了。速速前只能召喚物體,所以,我要召喚方天畫戟,這樣拿著方天畫戟的呂布就會一起傳過來——「速速前方天畫戟!」。

(神啊,我是不是做錯了什麼。)

糟糕,難道是因為我沒有夢見媽祖嗎......

(你最好什麼都不要唸,好好看接下來的文章。)

引入 HttpClientModule

現在,我們在 mock db 裏面存有英雄資料,透過 JSON-server 的協助,可以在 Angular 中來模擬使用 http 來呼叫 api 的行為。在 Angular 中,我們可以引入 HttpClientModule,並使用這個模組所擁有的提供商(provider)HttpClient, 來執行 http 請求。

在引入 HttpClientModule 模組之前,要先簡單說明「模組」(module)概念。「模組」概念解決的問題是,將應用程式更有組織地進行管理,而透過 import、export,就可以很好地達到複用程式碼的目的,在 JavaScript ES6 版本中,正式提出了模組系統 ,也就是「JS 模組」。

而在 Angular 中,模組化包含了兩個部分 :

  • JS 模組:JavasScript ES6 提供了模組,這讓我們可以很輕鬆地 import 、 export 程式碼。
  • Angular 模組:帶有 @NgModule 裝飾器標記的類別,在裝飾器裏面會放置元資料的物件,你也需要在這個物件中說明「宣告」(declarations)、「匯入」(imports)、「匯出」(exports)...分別有哪些類別。

我們可以先用「傭兵團」概念來思考 @NgModule 裝飾器記載的元資料:

  • 「宣告」(declarations):登記在這裡的類別,都是本傭兵團的傭兵。
  • 「匯入」(imports):這裏是有簽訂支援協定的傭兵團(module),你可以使用這些傭兵團有提供支援服務的傭兵。
  • 「匯出」(exports):本傭兵團的成員裡,有提供支援服務的傭兵會登記在這裡。

「傭兵團」概念或許可以說明在 NgModule 使用其他 NgModule 提供的支援服務,但這個概念也存在一個風險:那就是「支援協定並不是雙向的,而是單方面尋求支援」。意思是,你不能在 A 模組匯入 B 模組的情形下,同時在 B 模組匯入 A 模組,這會造成循環匯入的錯誤。對這個風險有印象,在日後遇到時,你就會知道發生了什麼事情,應該從何著手處理。

現在讓我們看看專案中必定存在的根模組 AppModule(app.module.ts):

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

上方的 import {xxx} from 'path'; 即為匯入 JS 模組的語法。而 @NgModule 裡面的各種陣列,即為此模組的相關內容。先看「宣告」(declarations) 陣列,這裏是放置宣告隸屬這個 module 檔案中的類別,現在這裡擁有 AppComponent 元件,如下:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'angular-tour-of-heroes';
}

可以看到,AppComponent 是一個帶有 @Component (元件)裝飾器的類別。你可以這麼想,帶有 @Component(元件) 、 @Directive(指令) 、@Pipe(管道) 裝飾器的類別,就是通過認證的傭兵。不同的裝飾器,用來說明傭兵負責的不同功用。

並且,在這個世界中不存在個體戶傭兵,所有想要從事傭兵工作的人,都必須加入傭兵團,也只能加入一個傭兵團。具體來說,AppComponent 只能登記在一個 NgModule 的「宣告」(declarations)中,無法再宣吿在其他 NgModule 下;如果沒有宣告在任何 NgModule 中,就沒有人可以使用 AppComponent。

此外,關於帶有元件/指令/管道不同裝飾器的類別,我們慢慢都會使用到。

現在,在根模組 AppModule 「匯入」(imports)陣列中加入 HttpClientModule【與其他傭兵團簽訂支援協議】,讓我們可以使用 HttpClientModule 匯出(exports)的內容【使用其他傭兵團有提供支援服務的傭兵】。

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Angular 就是一個 JavsScript 框架,連 NgModule 裝飾器,都是作為 JS 模組匯入到需要使用的地方的。

更詳盡的說明,請參考官方文件

新增 HeroListComponent 元件

為了更好的演示,讓我們用 Angular CLI 來建立一個 hero-list 元件。進入 src/app 目錄,這裡有個小技巧,在編輯器中,我們可以針對想要建立元件的資料夾點擊滑鼠右鍵,就可以發現「在終端機中打開」(Open in Integrated Terminal),點擊它,編輯器就會為我們打開終端機,並預設在此路徑中。

https://ithelp.ithome.com.tw/upload/images/20210917/20128395SfEdkCQhDs.png

接著就可以執行下列指令:

ng g c hero-list  // g for generate, c for component

Anglaur CLI 就會建立數個檔案,可能包含「.html」、「.ts」、「.css」、「.spec.ts」,並同時更新了 app.module.ts,讓我們查看更新的檔案:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';
import { HeroListComponent } from './hero-list/hero-list.component';

@NgModule({
  declarations: [
    AppComponent,
    HeroListComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

可以發現,Angualr CLI 幫我們在這個模組中宣告了 HeroListComponent 類別,因此,我們就可以在這個模組中使用它——以這裡來說,我們就可以在 AppComponent 中使用 HeroListComponent。

使用 HttpClient 取得英雄資料

因為在 app.module.ts 中匯入了 HttpClientModule 模組,我們就可以在宣告在 app.module.ts 的 HeroListComponent 裡,使用 HttpClientModule 匯出的內容,包括 HttpClient。

打開 hero-list.component.ts 檔案,在建構式(constructor)中注入 HttpClient:

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-hero-list',
  templateUrl: './hero-list.component.html',
  styleUrls: ['./hero-list.component.css']
})
export class HeroListComponent implements OnInit {

  constructor(
    private http: HttpClient
  ) { }

  ngOnInit(): void {
  }

}

然後我們使用它來取得英雄資料,在 ngOnInit 裏撰寫相關程式碼:

  constructor(
    private http: HttpClient
  ) { }
  
  ngOnInit(): void {
    this.http.get('api/heros').subscribe((heroList) => {
      console.log('HeroList', heroList);
    });
  }

如果現在用瀏覽器打開此 App,console 是不會印出 HeroList 的,因為我們根本還沒在 app 中使用 HeroListComponent 元件。

要怎麼使用元件呢?在 hero-list.component.ts@Component 裝飾器裡的元資料物件有個屬性 selector: 'app-hedo-list',這個就是我們可以寫在 *.html 檔案中、代表使用此元件的語法,類似 HTML 的 tag。

讓我們在根元件 app.component.html 中使用 HeroListComponent 元件:

<app-hero-list></app-hero-list>

如此我們就可以在 app 中看到如下畫面,代表我們確實取得了英雄資料:

https://ithelp.ithome.com.tw/upload/images/20210918/20128395lBCxupQyzU.png

小提醒:當你新增/刪除檔案後,必須重啟專案(ng serve)才會執行改變後的程式碼。

參考資料

  • 《哈利波特——火盃的考驗》,我只想說,寫這篇的體驗是「火焰的靠背」。
  • NgModule

上一篇
第 2 天 諸神早安晨之美|建立 Angular 專案、使用 JSON-server
下一篇
第 4 天 英雄有偶包怎麼辦|*ngFor、JsonPipe、Angular Material、Mat-Card、Mat-Button
系列文
關於我作夢變成工程師這檔事(Angular 篇)14
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言