iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 23
0
Modern Web

Angular 大師之路系列 第 23

[Angular 大師之路] Day 23 - 認識 InjectionToken


title: "[Angular 大師之路] 認識 InjectionToken"
date: 2018-11-07 22:24:16
category: "Angular 大師之路"
tags:
- Angular
- InjectionToken


在 Angular 中不是只有 service 可以當 token 被注入,我們也可以單純的注入某個物件,這個物件通常是一個全域的系統設定,或是單純的一個函數(function),這時候就會遇到一些問題,我們今天就來看看問題是什麼,以及如何解決!

類型:觀念

難度:4 顆星

實用度:5 顆星

一般情境

可以用我們之前學過的 useValue,類似以下程式:

export class Config {
  LogLevel: string
}

@NgModule({
  providers: [
    {
      provide: Config,
      useValue: { LogLevel: 'Error' }
    }
  ]
})
export class AppModule { }

這完全不是問題,但如果不想宣告成 class (畢竟會產生實際程式碼) 或是設定的不是物件,而是數值或字串呢?就會出問題了:

export interface Config {
  LogLevel: string
}

@NgModule({
  providers: [
    {
      // 錯誤,因為 interface 不會產生實體
      provide: Config,
      useValue: { LogLevel: 'Error' }
    }
  ]
})
export class AppModule { }

這時候可以使用 Angular 提供的 InjectionToken 來強制幫我們產生一個 token

使用 InjectionToken

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

export interface Config {
  LogLevel: string
}

// 替 interface 產生一個 token
// 參數的字串只是一個描述
export const CONFIG_TOKEN = new InjectionToken<Config>('config token');
// 基礎型別也不是問題
export const NAME_TOKEN = new InjectionToken<string>('name token');

@NgModule({
  providers: [
    {
      provide: CONFIG_TOKEN,
      useValue: { LogLevel: 'Error' }
    },
    {
      provide: NAME_TOKEN,
      useValue: 'Mike'
    }
  ]
})
export class AppModule { }

至於要如何取得 token 實體呢?可以使用 @Inject() 裝飾器,來告知要使用哪個 token 注入:

constructor(@Inject(CONFIG_TOKEN) private config: Config) {
  console.log(config);
}

Tree-shakable InjectionToken

InjectionToken 是非常特別的存在,通常都是提供給使用某個套件的人一些從外部設定的資訊,因此很多時候我們並不一定會去設定這個 token,但偏偏 InjectionToken 會真的產生實體,導致在進行 tree shaking 時無法過濾掉,跟傳統建立 service 的問題很類似,因此在 Angular 6 之後,也透過 providedIn: 'root' 的方法,來進行過濾:

const CONFIG_TOKEN = new InjectionToken<Config>('config token',
  {
    providedIn: 'root',
    factory: () => ({
      LogLevel: 'Error'
    })
  }
);

透過這種方式,當程式中有使用到 CONFIG_TOKEN 時,就會使用 factory: () => {} 產生的內容;若需要調整 token 的實體,在 @NgModuleproviders: [] 設定即可;而當完全沒有使用 CONFIG_TOKEN 時,這個被產生的內容也可以被過濾掉啦!

相關資源


上一篇
[Angular 大師之路] Day 22 - 各種在程式中取的注入 token 實體的方法
下一篇
[Angular 大師之路] Day 24 - 效能調校之認識 NgZone
系列文
Angular 大師之路30

1 則留言

0
jakeuj
iT邦新手 5 級 ‧ 2019-01-03 13:22:38

Console:

Uncaught Error: Can't resolve all parameters for AppComponent: (?).

Circular dependency detected:
src\app\app.component.ts -> src\app\app.module.ts -> src\app\app.component.ts

Q:Inject token value to global container in Angular 2, Can't resolve all parameters

A:You should move export let APP_CONFIG = new InjectionToken('app.config'); to a seperate file since it's causing a circular dependency issue.

Ref:https://stackoverflow.com/questions/44030089/inject-token-value-to-global-container-in-angular-2-cant-resolve-all-parameter?rq=1

我要留言

立即登入留言