第一個計數器案例:http://www.cnblogs.com/axel10/p/8589122.html
完成了計數器案例后,現在開始比較能夠完整的展示angular2+開發流程的案例:在線獲取用戶列表並展示,包含點擊刪除功能。希望在開始之前,你對typescript和rxjs有一定了解。
再重復一遍開發流程:
開始 -> 編寫數據模型 -> 編寫action -> 編寫redurces並配置到相應module -> 編寫services -> 編寫effects並配置到相應module -> 創建組件 -> 組件綁定數據模型 -> 渲染
第一步:編寫數據模型(app/models/user.ts)
export class User {
id: number;
name: string;
}
第二步:編寫action(app/actions/num.ts)
import {Action} from '@ngrx/store'; import {User} from '../models/user'; export enum ListActionType { Load = 'LOAD', LoadSuccess = 'LOAD_SUCCESS', RemoveUser = 'REMOVE_USER', RemoveUserSuccess = 'REMOVE_USER_SUCCESS', RemoveUserError = 'REMOVE_USER_ERROR' } export class Load implements Action { readonly type = ListActionType.Load; } export class LoadSuccess implements Action { readonly type = ListActionType.LoadSuccess; constructor(public payload: User[]) { } } export class RemoveUser implements Action { readonly type = ListActionType.RemoveUser; constructor(public payload: number) { } } export class RemoveUserSuccess implements Action { readonly type = ListActionType.RemoveUserSuccess; } export class RemoveUserError implements Action { readonly type = ListActionType.RemoveUserError; }
第三步:編寫redurcers(app/redurces/list.ts)
import {Action} from '@ngrx/store'; import {User} from '../models/user'; import {ListActionType, LoadSuccess, RemoveUser} from '../actions/list'; export interface State { loading: boolean; loaded: boolean; list: User[]; } const initialState: State = { loading: false, loaded: false, list: [] }; export const list = (state = initialState, action: Action) => { switch (action.type) { case ListActionType.Load: console.log('load....'); return { ...state, loading: true, }; case ListActionType.LoadSuccess: console.log('load success'); const myA = (<LoadSuccess>action).payload; console.log(myA); return { ...state, loaded: true, loading: false, list: myA }; case ListActionType.RemoveUser: console.log('remove user'); const userId = (<RemoveUser>action).payload; state.list = state.list.filter(function (item) { return item.id !== userId; }); return {...state}; default: return state; } };
配置redurcer(app/app.module.ts)
imports: [ BrowserModule, RouterModule.forRoot(routes), StoreModule.forRoot({ modelNum, list}), //配置redurcer ],
第四步:編寫services(app/services/ListService.ts)
import {Injectable} from '@angular/core'; import {HttpClient} from '@angular/common/http'; import {Observable} from 'rxjs/Observable'; import {User} from '../models/user'; @Injectable() export class ListService { public getList(): Observable<any> { return this.http.get<{ users: User[] }>('/api/users.json'); } public removeUser(): Observable<any> { return Observable.create(function (observer) { observer.next('true'); }); } constructor(private http: HttpClient) { } }
第五步:編寫effects:
import {Injectable} from '@angular/core'; import {Actions, Effect, ofType} from '@ngrx/effects'; import {Observable} from 'rxjs/Observable'; import {Action} from '@ngrx/store'; import {ListActionType, Load, LoadSuccess, RemoveUser, RemoveUserError, RemoveUserSuccess} from '../actions/list'; import {catchError, map, switchMap} from 'rxjs/operators'; import {ListService} from '../services/ListService'; import {of} from 'rxjs/observable/of'; @Injectable() export class ListEffects { @Effect() loadList$: Observable<Action> = this.action$.pipe( //rxjs寫法。loadList$是effect名,在外部沒有用到,可以隨便起。 ofType<Load>(ListActionType.Load), switchMap(action => { return this.listService.getList().pipe(map( users => { return new LoadSuccess(users); } )); }) ); @Effect() removeUser$: Observable<Action> = this.action$.pipe( ofType<RemoveUser>(ListActionType.RemoveUser), switchMap(_ => { return this.listService.removeUser().pipe( map(res => { console.log(res); if (res === 'true') { return new RemoveUserSuccess(); } else { return new RemoveUserError(); } }), catchError(err => of(new RemoveUserError())) ); }) ); constructor(private action$: Actions, private listService: ListService) { } }
記得在app.module.ts配置effects和HttpClient:
imports: [
BrowserModule,
RouterModule.forRoot(routes),
StoreModule.forRoot({modelNum, list}),
EffectsModule.forRoot([ListEffects]),
HttpClientModule
],
第六步:創建組件
ng g component list
第七步:組件綁定數據模型(連帶完成第八步)
組件ts文件:
import {Component, OnInit} from '@angular/core'; import {Store} from '@ngrx/store'; import * as list from '../actions/list'; import {State} from '../reducers/list'; import {User} from '../models/user'; @Component({ selector: 'app-list', templateUrl: './list.component.html', styleUrls: ['./list.component.scss'] }) export class ListComponent implements OnInit { public list: User[]; constructor(private store: Store<any>) { this.store.select('list').subscribe(_list => { if (_list) { console.log(_list); console.log(_list.list); this.list = _list.list; } }); } removeUser(id) { console.log(id); this.store.dispatch(new list.RemoveUser(id)); } ngOnInit() { this.store.dispatch(new list.Load()); } }
組件html文件:
<div> list 請嘗試點擊上半部分的li。 <ul> <li *ngFor="let item of list" (click)="removeUser(item.id)">{{item.name}}</li> </ul> <app-list-body></app-list-body> <br/> <a routerLink="/model">to counter demo</a> </div>
最后配置路由:
import {Routes} from '@angular/router';
import {IndexComponent} from './index/index.component';
import {ModelDemoComponent} from './model-demo/model-demo.component';
import {ListComponent} from './list/list.component';
export const routes: Routes = [
{
path: 'list',
component: ListComponent
},
{
path: 'model',
component: ModelDemoComponent
},
{
path: '**',
redirectTo: 'list'
}
];
到此本案例結束。如果想要更加復雜的案例可以到ngrx的github獲取。https://github.com/ngrx/platform