前集回顧webpack
上一章裏咱們在AppComponent
裏經過組合InputItem
、 CheckableItem
、 Counter
三個組件,並經過Unidirectional Data Flow
(單向數據流)的方式把她們驅動起來。今天這章,咱們講講angular2
裏的service
。git
本章源碼:servicegithub
本章使用angular2
版本爲:2.4.5
,webpack
版本爲: 2.2.0
web
先來看看咱們將要完成的效果圖:typescript
(注意動畫部分),在上一章的基礎上咱們加入了初始化數據,在數據加載完成前會有一個loading
,數據準備好以後loading
消失,列表顯現。shell
每章都會提一下,先設計使用場景(這種方式,咱們稱之爲"BDD",不瞭解的朋友參考以BDD手寫依賴注入(dependency injection))。npm
ts/app.ts
import {Component, OnInit} from '@angular/core'; import {Item} from './CheckableItem'; //引入本章主題ItemService import {ItemService} from './ItemService'; @Component({ selector: 'my-app', template: ` <h1>My First Angular 2 App</h1> <input-item (onItemAdded)="addItem($event)"></input-item> <checkable-item *ngFor="let itemInfo of items; let i = index" [item]="itemInfo" (onItemClicked)="toggle($event, i)"> </checkable-item> <p *ngIf="loading">Loading</p> <counter *ngIf="!loading" [items]="items"></counter> `, directives: [InputItem, CheckableItem, Counter], //注入ItemService providers: [ItemService] }) export class AppComponent implements OnInit { items: Item[] = []; //聲明loading狀態,初始值爲true loading: boolean = true; //經過構造器自動獲取ItemService實例 constructor(private _itemService: ItemService) { } //在組件初始化之後調用ItemService獲取初始化數據 ngOnInit() { this._itemService .getItems() .then(data => { //重置loading狀態爲false this.loading = false; //設置初始值 this.items = data; }); } addItem(item: Item) { this.items = [...this.items, item]; } toggle(item: Item, index: number) { this.items = [ ...this.items.slice(0, index), { isChecked: !item.isChecked, txt: item.txt }, ...this.items.slice(index + 1) ]; } }
ItemService
touch ts/ItemService.ts
向剛建立的ts/ItemService.ts
中,添加以下內容:segmentfault
import {Injectable} from '@angular/core'; import {Item} from './CheckableItem'; //用Injectable裝飾器聲明該類可被依賴注入 @Injectable() export class ItemService { //設置一個初始值數組 private items: Item[] = [ { isChecked: true, txt: 'Learn JavaScript' }, { isChecked: false, txt: 'Learn TypeScript' }, { isChecked: false, txt: 'Learn Angular2' } ]; //提供一個方法,返回初始數據的Promise getItems(): Promise<Array<Item>> { return new Promise((resolve, reject) => { //這裏手動作延遲是爲了模擬網絡請求 setTimeout(() => { resolve(this.items); }, 1500); }); } }
本章內容比較簡單,寫到這裏差很少算結束了(其實尚未哦!),先來跑跑看數組
npm start
OK,我確信這個代碼是能夠運行的,那到底什麼是service
?咱們如今來對着代碼講一講。網絡
service
是可被替換的
service
必須經過依賴注入使用
service
一般用做數據存取等應用中可公用邏輯部分
必須經過@Injectable
裝飾器聲明
import {Injectable} from '@angular/core'; @Injectable() export class ItemService { }
引入service
import {ItemService} from './ItemService';
切忌不要自做多情的
new
她哦!!!!!
構造器獲取實例
constructor(private _itemService: ItemService) { }
自動注入實例
就像directives
那樣,添加到@Component
的metadata中
providers: [ItemService]
就這麼簡單,so easy 有木有?
那麼咱們說,到這裏就結束了嗎?請看下面,template
裏有這麼一段:
用了*ngFor
將items
列表化
用了*ngIf
控制loading
的顯示狀態
是否是感受有點兒矬了,若是能有個單獨的ItemList
組件該多好?像這樣使用:
import {Component, OnInit} from '@angular/core'; import {Item} from './CheckableItem'; import {ItemService} from './ItemService'; @Component({ selector: 'my-app', template: ` <h1>My First Angular 2 App</h1> <input-item (onItemAdded)="addItem($event)"></input-item> <item-list [data]="items" (onItemClicked)="toggle($event)" [showLoading]="loading"> </item-list> <counter *ngIf="!loading" [items]="items"></counter> `, providers: [ItemService] }) export class AppComponent implements OnInit { items: Item[] = []; loading: boolean = true; constructor(private _itemService: ItemService) { } ngOnInit() { this._itemService .getItems() .then(data => { this.loading = false; this.items = data; }); } addItem(item: Item) { this.items = [...this.items, item]; } toggle(e: { item: Item, index: number }) { this.items = [ ...this.items.slice(0, e.index), { isChecked: !e.item.isChecked, txt: e.item.txt }, ...this.items.slice(e.index + 1) ]; } }
ItemList
touch ts/ItemList.ts
向剛建立的ts/ItemList.ts
中,添加以下內容:
import {Component, Input, Output, EventEmitter, ChangeDetectionStrategy} from '@angular/core'; import { Item } from './CheckableItem'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'item-list', template: ` <checkable-item *ngFor="let item of data; let i=index" [item]="item" (onItemClicked)="clickItem($event, i)"> </checkable-item> <p *ngIf="showLoading">Loading</p> ` }) export class ItemList { @Input() data: Item[]; @Input() showLoading: boolean; @Output() onItemClicked = new EventEmitter(); clickItem(e: Item, i: number) { this.onItemClicked.emit({ item: e, index: i }); } }
一切都結束了,效果仍然沒有變,仍是很屌的樣子!!!!
下回預告:使用Routing