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
配置依赖对象。