- 升级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 下来,方便读者练习)