目錄
- Angular 4 依賴注入教程之一 依賴注入簡介
- Angular 4 依賴注入教程之二 組件服務(wù)注入
- Angular 4 依賴注入教程之三 ClassProvider的使用
- Angular 4 依賴注入教程之四 FactoryProvider的使用
- Angular 4 依賴注入教程之五 FactoryProvider配置依賴對象
- Angular 4 依賴注入教程之六 Injectable 裝飾器
- Angular 4 依賴注入教程之七 ValueProvider的使用
- Angular 4 依賴注入教程之八 InjectToken的使用
閱讀須知
本系列教程的開發(fā)環(huán)境及開發(fā)語言:
基礎(chǔ)知識(shí)
ValueProvider 的作用
ValueProvider 用于告訴 Injector (注入器),但使用 Token
獲取依賴對象時(shí)阵谚,則返回 useValue
指定的值伪货。
ValueProvider 的使用
const provider: ValueProvider = {provide: 'someToken', useValue: 'someValue'};
ValueProvider 接口
export interface ValueProvider {
// 用于設(shè)置與依賴對象關(guān)聯(lián)的Token值监氢,Token值可能是Type钉凌、InjectionToken损同、
// OpaqueToken的實(shí)例或字符串
provide: any;
// 設(shè)置注入的對象
useValue: any;
// 用于標(biāo)識(shí)是否multiple providers,若是multiple類型慈鸠,則返回與Token關(guān)聯(lián)的依賴
// 對象列表
multi?: boolean;
}
json-server 簡介
json-server 用于基于 JSON 數(shù)據(jù)快速地創(chuàng)建本地模擬的 REST
API蓝谨。
json-server 的安裝
npm install -g json-server
json-server 的使用
json-server --watch db.json
Angular CLI 代理配置
創(chuàng)建 proxy.conf.json
文件
{
"/heros": {
"target": "http://localhost:3000",
"secure": false
}
}
更新 package.json
文件
{
"scripts": {
"start": "ng serve --proxy-config proxy.conf.json",
}
}
ValueProvider
介紹完基礎(chǔ)知識(shí),我們馬上進(jìn)入正題青团。不知道大家是否還記得譬巫,在 "組件服務(wù)注入" 文章中提到的內(nèi)容:
難道一切就這么結(jié)束了,No督笆! No芦昔!別忘記了我們這節(jié)課的主題是介紹如何在組件中注入服務(wù)。在目前的
HeroComponent
組件胖腾,我們的英雄列表信息是固定的,在實(shí)際的開發(fā)場景中瘪松,一般需要從遠(yuǎn)程服務(wù)器獲取相應(yīng)的信息咸作。
接下來我們將重構(gòu)我們的 HeroService
服務(wù),從 API 接口中獲取英雄數(shù)據(jù)宵睦。要使用 Angular 的 Http
服務(wù)记罚,首先需要在 AppModule
模塊中導(dǎo)入 HttpModule
,然后在 HeroService
類的構(gòu)造函數(shù)中注入 Http
服務(wù)壳嚎。
更新 HeroService 服務(wù)
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import { LoggerService } from './logger.service';
@Injectable()
export class HeroService {
constructor(private loggerService: LoggerService,
private http: Http) { }
apiUrl = 'http://localhost:4200/heros';
getHeros(): Observable<Array<{ id: number; name: string }>> {
this.loggerService.log('Fetching heros...');
return this.http.get(this.apiUrl)
.map(res => res.json())
}
}
在 HeroService
服務(wù)中桐智,我們通過注入 Http
服務(wù)對象的 get()
方法發(fā)送 HTTP
請求末早,從而從 API
接口中獲取英雄的數(shù)據(jù)。
更新 HeroComponent 組件
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.heroService.getHeros()
.subscribe(res => {
this.heros = res;
});
}
}
更新完上述代碼说庭,成功保存后然磷,你會(huì)發(fā)現(xiàn) http://localhost:4200/
頁面,一片空白刊驴。這就對了姿搜,因?yàn)槲覀冞€沒有啟動(dòng)本地的 json-server
服務(wù)器。接下來我們來配置并啟動(dòng)本地的 json-server
服務(wù)器:
創(chuàng)建 heros.json
文件
{
"heros": [
{"id":11,"name":"Mr. Nice"},
{"id":12,"name":"Narco"},
{"id":13,"name":"Bombasto"},
{"id":14,"name":"Celeritas"},
{"id":15,"name":"Magneta"}
]
}
啟動(dòng) json-server
服務(wù)器
json-server --watch heros.json
當(dāng)成功啟動(dòng) json-server
服務(wù)器捆憎,在命令行中舅柜,你將看到以下輸出信息:
\{^_^}/ hi!
Loading heros.json
Done
這表示本地 json-server
已經(jīng)成功啟動(dòng),此時(shí)重新刷新以下 http://localhost:4200/
頁面躲惰,你將看到以下信息:
ID: 11 - Name: Mr. Nice
ID: 12 - Name: Narco
ID: 13 - Name: Bombasto
ID: 14 - Name: Celeritas
ID: 15 - Name: Magneta
程序終于又正常運(yùn)行了致份,但注意到 HeroService
服務(wù)中,我們通過以下方式定義 API
接口地址:
@Injectable()
export class HeroService {
...
apiUrl = 'http://localhost:4200/heros';
}
這種方式有個(gè)問題础拨,假設(shè)其它服務(wù)也要使用該地址氮块,那么就得按照同樣的方式去定義 API
接口地址。另外假設(shè) API
接口地址需要更新太伊,那就需要修改多個(gè)地方雇锡。針對上述問題,我們可以使用 ValueProvider
來解決問題僚焦。
使用 ValueProvider
@NgModule({
...,
providers: [
{
provide: 'apiUrl',
useValue: 'http://localhost:4200/heros'
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
更新 HeroService 服務(wù)
@Injectable()
export class HeroService {
constructor(private loggerService: LoggerService,
private http: Http,
@Inject('apiUrl') private apiUrl) { }
getHeros(): Observable<Array<{ id: number; name: string }>> {
this.loggerService.log('Fetching heros...');
return this.http.get(this.apiUrl)
.map(res => res.json())
}
}
在 HeroService
類的構(gòu)造函數(shù)中锰提,我們通過 @Inject('apiUrl')
方式,注入 apiUrl
該 Token
對應(yīng)的依賴對象芳悲,即 'http://localhost:4200/heros'
立肘。為什么不能使用 private apiUrl: 'apiUrl'
的方式,希望讀者好好回憶一下名扛,之前我們介紹過的相關(guān)內(nèi)容谅年。
以上代碼成功運(yùn)行后,在 http://localhost:4200/
頁面肮韧,我們將看到預(yù)期的結(jié)果:
ID: 11 - Name: Mr. Nice
ID: 12 - Name: Narco
ID: 13 - Name: Bombasto
ID: 14 - Name: Celeritas
ID: 15 - Name: Magneta
我有話說
為什么在構(gòu)造函數(shù)中融蹂,非 Type 類型的參數(shù)只能用 @Inject(Something) 的方式注入 ?
因?yàn)?Type
類型的對象弄企,會(huì)被 TypeScript
編譯器編譯超燃。即我們通過 class
關(guān)鍵字聲明的服務(wù),最終都會(huì)編譯成 ES5
的函數(shù)對象拘领。
在構(gòu)造函數(shù)中意乓,Type 類型的參數(shù)能用 @Inject(Type) 的方式注入么?
Type
類型的參數(shù)也能使用 @Inject(Type)
的方式注入约素,具體如下:
constructor(@Inject(Http) private http) { }
同樣也可以使用以下方式:
constructor(@Inject(Http) private http: Http) { }
第一種方式雖然可以正常編譯届良,但 IDE 會(huì)有如下的提示信息:
[ts] Parameter 'http' implicitly has an 'any' type.
第二種方式笆凌,雖然 Angular 內(nèi)部會(huì)合并 design:paramtypes 與 parameters 內(nèi)的 metadata 信息,但本人覺得是有點(diǎn)冗余了士葫。 總而言之乞而,若果是 Type 類型的參數(shù),推薦使用下面的方式:
constructor(private http: Http) { }
若有興趣了解 Inject
裝飾器的詳細(xì)信息为障,請參考 Angular 2 Inject 這篇文章晦闰。