Angular 4 依賴注入教程之四 FactoryProvider的使用typescript
Angular 4 依賴注入教程之六 Injectable 裝飾器bootstrap
Angular 4 依賴注入教程之七 ValueProvider的使用segmentfault
本系列教程的開發環境及開發語言:ide
FactoryProvider 用於告訴 Injector (注入器),經過調用 useFactory
對應的函數,返回 Token
對應的依賴對象。
function serviceFactory() { return new Service(); } const provider: FactoryProvider = { provide: 'someToken', useFactory: serviceFactory, deps: [] };
export interface FactoryProvider { // 用於設置與依賴對象關聯的Token值,Token值多是Type、InjectionToken、 // OpaqueToken的實例或字符串 provide: any; // 設置用於建立對象的工廠函數 useFactory: Function; // 依賴對象列表 deps?: any[]; // 用於標識是否multiple providers,如果multiple類型,則返回與Token關聯的依賴 // 對象列表 multi?: boolean; }
介紹完基礎知識,接下來咱們立刻進入正題。不知道你們是否還記得,以前咱們建立過的 HeroComponent
組件:
import { Component, OnInit } from '@angular/core'; import { HeroService } from '../hero.service'; @Component({ selector: 'app-hero', template: ` <ul> <li *ngFor="let hero of heros"> ID: {{hero.id}} - Name: {{hero.name}} </li> </ul> ` }) export class HeroComponent implements OnInit { constructor(private heroService: HeroService) { } heros: Array<{ id: number; name: string }>; ngOnInit() { this.heros = this.heroService.getHeros(); } }
那麼如今問題來了,假設咱們想在獲取英雄數據時,輸出調試信息,那應該怎麼辦?What ~,這個問題不是很簡單麼,直接使用 console.log
API 輸出相應信息不就好了麼:
console.log('Fetching heros...'); this.heros = this.heroService.getHeros();
那問題又來了,若是多個組件都使用 HeroService
去獲取英雄數據,那麼是否是每一個組件都得添加對應的語句。另外若是要修改輸出的調試信息,那就得修改程序中多個地方。其實咱們通常只須要在開發階段,輸出調試信息,所以上面的方案不合理,也不夠靈活。
其實咱們能夠借鑑以前引入 HeroService
服務的思路,建立一個 LoggerService
來解決上面提到的問題。
export class LoggerService { constructor(private enable: boolean) { } log(message: string) { if(this.enable) { console.log(`LoggerService: ${message}`); } } }
@NgModule({ ... providers: [ HeroService, LoggerService ], bootstrap: [AppComponent] }) export class AppModule { }
import { Component, OnInit } from '@angular/core'; import { HeroService } from '../hero.service'; import { LoggerService } from './../logger.service'; @Component({ selector: 'app-hero', template: ` <ul> <li *ngFor="let hero of heros"> ID: {{hero.id}} - Name: {{hero.name}} </li> </ul> ` }) export class HeroComponent implements OnInit { heros: Array<{ id: number; name: string }>; constructor(private heroService: HeroService, private loggerService: LoggerService) { } ngOnInit() { this.loggerService.log('Fetching heros...'); this.heros = this.heroService.getHeros(); } }
以上代碼運行後會拋出如下異常信息:
Uncaught Error: Can't resolve all parameters for LoggerService: (?).
有的讀者,眼睛一亮,多是你在建立 LoggerService
服務時,忘記使用 @Injectable
裝飾器了。哈哈,其實我是故意的,但我加上 @Injectable()
後,仍是拋出瞭如下異常:
ERROR Error: No provider for Boolean!
爲何會出現上面的異常信息呢?咱們再看一下前面建立的 LoggerService
服務:
export class LoggerService { constructor(private enable: boolean) { } // ... }
在 Angular 中咱們經過構造注入的方式注入依賴對象, private enable: boolean
這種方式表示咱們要注入 Type
類型的對象。而後 boolean
是表示基本數據類型,並非所需的 Type
類型:
export function isType(v: any): v is Type<any> { return typeof v === 'function'; }
接下來咱們再來看一下最先拋出的異常:
Uncaught Error: Can't resolve all parameters for LoggerService: (?).
其實問題的答應也在 LoggerService
類的構造函數中,在建立 LoggerService
對象時,咱們須要設置 enable
參數的值。那麼如何解決呢? 固然可使用咱們的主角 - FactoryProvider
。具體以下:
@NgModule({ ..., providers: [ HeroService, { provide: LoggerService, useFactory: () => { return new LoggerService(true); } } ], bootstrap: [AppComponent] }) export class AppModule { }
當更新完代碼,而後再來一個華麗的保存操做,最後打開你的控制檯,你將看到預期的輸出信息:
LoggerService: Fetching heros...
難道就這樣結束了,關於 FactoryProvider
的相關內容先告一段落,下一篇咱們將介紹如何使用 FactoryProvider
配置依賴對象。