上方廣告

2017年7月20日 星期四

[Angular學習紀錄] 網站載入前讀取config設定檔參數

應用程式執行前讀取 config 檔案內的參數,這是常見的開發方式,但若把參數定義在 TypeScript 檔案內,經過編譯後,所撰寫的類別都會被整併到 main.js 檔案內,所以若需要調整 config 參數,就必須要打開 main.js 然後在凌亂的 JavaScript檔案內找到參數,在修改它,這可能不是你樂見的。

理想的狀態應該是,把參數檔案定義在一個不會被編譯的檔案內,Ex. JSON檔,然後要使用的時候再去讀取它,對吧~

當然不對,這也是筆者一開始的思維,但當要讀取 .json 檔案的時候,卻發現必須使用 http 、使用 http 、使用 http 來取得參數,若還沒發現事情的嚴重性,筆者大概說明一下,http是一個非同步回傳的類別,所以若要取得參數,就必須要在等待資料回傳後再繼續進行後續的作業,這樣整個應用程式會變得非常的複雜。


Angular正規的使用方式,應該是建立一個 Service,該服務用來載入參數,並且可視需求注入各類別,供各類別使用,下文將示範如何建立一個服務來取得必要的參數資料。


建立服務類別 ConfigService


建立一個服務類別config.service.ts,該類別用來初始化載入參數,和提供參數。
@Injectable()
export class ConfigService {

  private _config: any;

  //提供姓名
  get name() {
    return !this._config ? "沒載入成功" : this._config.name;
  }

  constructor(private http: Http) { }

  //供第一次讀取config時呼叫,之後就不會使用到了
  load() {
    console.log("ConfigService load");
    return this.http.get('assets/config.json')
      .map(res => res.json())
      .toPromise()
      .then(data => {
        this._config = data;
        return data;
      })
  }
}


Module Providers


在Module Providers內聲明該服務為,APP_INITIALIZER,參考語法如下。
providers: [
ConfigService,
{
  provide: APP_INITIALIZER,
  useFactory: (config: ConfigService) => { return () => config.load(); }, 
  deps: [ConfigService],
  multi: true
},
],


實作完以上兩個步驟後,整個應用程式的執行順序將會從原本
AppModule -> ConfigService -> AppComponent 變成
ConfigService -> AppModule -> AppComponent

也就是說,宣告了ConfigService這個服務必須在APP初始化的時候就載入了,其它的必須要等待它完成才繼續進行,如此,就可以達到期望的使用方式了。




本文撰寫時Angular版本為v4.0。

本文範例下載 : Github,使用Angular CLI。