- 升級Angular 4.1 -> 4.3
- 添加
json-server
模擬數據- 建立本身的 http
- 完成一次表單提交
由於 httpClient 支持的最低 Angular 版本爲 4.3, 因此須要先升級咱們的 Angular
以下圖 配置 package.json
css
而後須要修改一個配置項,兼容到 4.3.0 版本tsconfig.json
添加一行html
"paths": { "@angular/*": ["../node_modules/@angular/*"] }
這樣便完成了版本的升級node
json-server
模擬數據咱們完成一個數據查詢,提交須要一些模擬數據,json-server
工具能夠幫助咱們,全局安裝git
npm i json-server -g
github
在 package.json
中的 scripts 添加一行ajax
"db:mock": "json-server --watch ./db/db.json"
咱們如今須要建立一個 json 文件,用於裝載咱們的模擬數據,根據上述命令,在項目根目錄建立npm
db/db.json
json
{ "user": [ { "id": 1, "firstName": "張小", "emailAddress": "15135131@qq.com", "brave": "solid" } ] }
打開一個命令行窗口,在項目文件夾執行npm run db:mock
咱們的 json-server
就啓動了,如今來回到咱們的項目redux
在提交表單以前,咱們須要 ajax
去提交咱們的數據,這時候涉及到服務,數據驗證,處理 response
,這時候須要建立一套 http/httpClient 去負責這些任務。後端
建立一個 http 工具類,負責提供 header, host, 以及完成拼接 url, 參數的工做。 根據咱們的 json-server
配置,來建立這個文件。
api/http/http.service.ts
import { Injectable } from "@angular/core"; import { HttpHeaders } from "@angular/common/http"; @Injectable() export class HttpComponentUtil { public headers = new HttpHeaders({ "Content-Type": "application/json" }); private url: string = "http://localhost:3000/"; public getUrl(url: string): string { return this.url + url; } }
建立 http 的統一攔截服務,作統一攔截,而且在將來作一些通用的工做api/http/noopInterceptor.ts
import { Injectable } from "@angular/core"; import { Observable } from 'rxjs/Observable'; import 'rxjs/Rx'; import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse } from "@angular/common/http"; @Injectable() export class NoopInterceptor implements HttpInterceptor { intercept( req: HttpRequest<any>, next: HttpHandler ): Observable<HttpEvent<any>> { const started = Date.now(); return next .handle(req) .do(event => { if (event instanceof HttpResponse) { const elapsed = Date.now() - started; console.log(`Request for ${req.urlWithParams} took ${elapsed} ms.`); } }); } }
http 的統一攔截,還須要在 appModule.ts
中單獨註冊app.module.ts
@NgModule({ ... providers: [ ... { provide: HTTP_INTERCEPTORS, useClass: NoopInterceptor, multi: true, } ] });
當 http 請求出錯時,須要作一些錯誤處理,如今來建立一個服務,作統一的錯誤處理api/http/handle.service.ts
import { Injectable, Inject } from '@angular/core'; import { Location } from '@angular/common'; import { Router, ActivatedRoute, Params } from '@angular/router'; import { Observable } from 'rxjs/Observable'; import swal from 'sweetalert2'; @Injectable() export class HandleService { constructor( private router: Router, private _location: Location ) { }; // 處理系統錯誤 handleError(err: any): Observable<any> { let errMsg = '發生未知錯誤,請重試'; if (typeof err == 'object' && err.status !== undefined) { if (err.status == 404) { errMsg = '服務器處理異常,請重試'; } else if (err.status == 401) { swal('當前頁面無權限查看', '', 'warning'); this._location.back(); return Observable.empty(); } else if (err.status == 504) { errMsg = '服務器請求超時,請重試'; } else if (err.status == 503) { errMsg = '相關服務正在部署發佈,請稍等'; } else { errMsg = err.json().message; } } swal(errMsg, '', 'error'); return Observable.empty(); } // 處理returnCode 這裏假定接口 200 經過後,後端返回的狀態碼爲 returnCode handleStatus(result: any): Observable<any> { switch ((result.returnCode && String(result.returnCode)) || "201") { case '201': return Observable.of(result); case '1000': return Observable.of(result); case '1001': swal('當前頁面無權限查看', '', 'warning'); this._location.back(); return Observable.empty(); case '1002': // 數據爲空 return Observable.of(result); default: swal('沒法識別的錯誤碼,請聯繫管理員', '', 'error'); return Observable.empty(); } } }
上面有兩個依賴注入,須要在 providers 注入,如今建立一個文件來提供注入api/index.ts
import { HttpComponentUtil } from './http/http.service'; import { HandleService } from './http/handle.service'; export const API_SERVICE = [ HttpComponentUtil, HandleService ];
pages/pages.module.ts
中注入這兩個服務
@NgModule({ imports: [CommonModule, AppTranslationModule, NgaModule, routing], declarations: [Pages], providers: [ ...API_SERVICE ] })
到這裏,http 服務建立完成,下半部分在表單提交時完成,屬於應用層
完成表單提交,須要用到 ajax, 咱們將使用 httpClient 完成 ajax 的工做,咱們須要先注入 HttpClientModule, 在 nga.module.ts
中注入,這裏不貼代碼了
注入完成後,如今來開始編寫咱們的各項請求實例。
由於是表單提交,因此咱們新建一個服務,由它來完成表單提交的最後一步。theme/components/dynamic-form/dynamic-form.service.ts
import { Observable } from "rxjs/Rx"; import { Injectable } from "@angular/core"; import { HttpClient, HttpEvent, HttpHeaders } from "@angular/common/http"; import { HttpComponentUtil } from '../../../pages/api/http/http.service'; import { HandleService } from '../../../pages/api/http/handle.service'; @Injectable() export class DynamicFormService { constructor( private http: HttpClient, private https: HttpComponentUtil, private handleService: HandleService ) {} public getList(url: string, params: {} = {}): Observable<any> { return new Observable(); } /** * * * @param {string} url * @param {{}} [params={}] 請求入參的 body,參數 * @returns {Observable<any>} 返回一個可供訂閱的觀察者對象 * @memberof DynamicFormService */ public saveQuery(url: string, params: {} = {}): Observable<any> { let api_url: string = this.https.getUrl(url); // 利用公用的 http 服務,拼接獲取url return this.http.post(api_url, params, { headers: this.https.headers }) .map((res: any) => (<any>this.handleService.handleStatus(res)).value || undefined) // 捕獲錯誤碼 .catch(err => this.handleService.handleError(err)); // 捕獲系統錯誤 } }
上面構建了包含一個 saveQuery 功能的服務, 代碼已經添加註釋,能夠仔細研讀一下。
saveQuery 的兩個參數,params 應該由動態表單直接獲取提供,url 應該由頁面提供, 因此 DynamicFormComponent
應該接入一個 Input
參數
@Input() config: FormConfig;
dynamic-form/form-base.ts
export interface FormConfig { url: string; }
如今須要在頁面中,把 config
參數傳入組件user-add.component.ts
... export class UserAddComponent { public UserAddConfig: FormConfig = { url: "user" } ... }
user-add.component.html
<h1> 新增用戶組件 </h1> <div class="user-form"> <dynamic-form [questions]="UserAddQuestions" [config]="UserAddConfig"></dynamic-form> </div>
如今回到組件,咱們將完成咱們的提交表單操做,如今思考兩個問題,提交成功後的操做
因此咱們的組件應該是dynamic-form.component.ts
import { Component, Input, OnInit } from "@angular/core"; import { Location } from '@angular/common'; import { FormGroup } from "@angular/forms"; import { QuestionBase } from "../dynamic-form-components/dynamic-form-base/question-base"; import { QuestionControlService } from "./question-control.service"; import { DynamicFormService } from "./dynamic-form.service"; import "style-loader!./dynamic-fom-components.component.scss"; import { FormConfig } from './form-base'; import swal from "sweetalert2"; @Component({ selector: "dynamic-form", templateUrl: "./dynamic-form.component.html", styleUrls: ["./dynamic-form.component.scss"], providers: [QuestionControlService, DynamicFormService] }) export class DynamicFormComponent implements OnInit { @Input() questions: QuestionBase<any>[] = []; @Input() config: FormConfig; form: FormGroup; payload = ""; constructor( private qcs: QuestionControlService, private service: DynamicFormService, private _location: Location ) {} ngOnInit() { this.form = this.qcs.toFormGroup(this.questions); } onSubmit() { this.payload = JSON.stringify(this.form.value); this.service.saveQuery(this.config.url, this.payload) .subscribe((res: Response) => { console.log(res); swal("success","","success").then(() => { this._location.back(); }); }) } }
這裏使用到了 sweetalert2
組件,須要讀者自行安裝,而且在pages.component.ts
中引入樣式
import "style-loader!sweetalert2/dist/sweetalert2.min.css";
如今打開瀏覽器,來測試一下咱們剛纔的頁面,測試結果以下
添加成功和失敗,都有對應提示,而且提交成功後會返回到上一頁,如今來看看 db.json
,以下圖,數據也被添加進了json!
咱們的數據已經存入,下章就來說解,如何搭建一個動態表格組件,來展現咱們的數據,後續會把增刪改查功能一一介紹,在介紹完基礎組件後,會注入 redux 方便咱們的狀態管理
(此章代碼在ng2-admin 的 httpclient-submit 分支上,能夠pull 下來,方便讀者練習)