美文网首页Angular 4.x 修仙之路
使用ng2-admin搭建成熟可靠的后台系统 -- ng2-ad

使用ng2-admin搭建成熟可靠的后台系统 -- ng2-ad

作者: 昵称不用太拉风 | 来源:发表于2018-01-03 11:41 被阅读39次

    使用ng2-admin搭建成熟可靠的后台系统 -- ng2-admin(五)

    完善动态表单组件

    • 升级Angular 4.1 -> 4.3

    • 添加 json-server 模拟数据

    • 创建自己的 http

    • 完成一次表单提交

    升级Angular 4.1 -> 4.3(版本大于 4.3.0 可跳过)

    因为 httpClient 支持的最低 Angular 版本为 4.3, 所以需要先升级我们的 Angular
    如下图 配置 package.json

    mark
    mark

    然后需要修改一个配置项,兼容到 4.3.0 版本
    tsconfig.json 添加一行

    "paths": { "@angular/*": ["../node_modules/@angular/*"] }
    

    这样便完成了版本的升级

    添加 json-server 模拟数据

    我们完成一个数据查询,提交需要一些模拟数据,json-server 工具可以帮助我们,全局安装

    npm i json-server -g

    package.json 中的 scripts 添加一行

    "db:mock": "json-server --watch ./db/db.json"
    

    我们现在需要创建一个 json 文件,用于装载我们的模拟数据,根据上述命令,在项目根目录创建

    db/db.json

    {
      "user": [
        {
          "id": 1,
          "firstName": "张小",
          "emailAddress": "15135131@qq.com",
          "brave": "solid"
        }
      ]
    }
    

    打开一个命令行窗口,在项目文件夹执行
    npm run db:mock
    我们的 json-server 就启动了,现在来回到我们的项目

    创建自己的 http

    在提交表单之前,我们需要 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";
    

    现在打开浏览器,来测试一下我们刚才的页面,测试结果如下


    mark
    mark

    添加成功和失败,都有对应提示,并且提交成功后会返回到上一页,现在来看看 db.json,如下图,数据也被添加进了json!

    mark

    我们的数据已经存入,下章就来讲解,如何搭建一个动态表格组件,来展示我们的数据,后续会把增删改查功能一一介绍,在介绍完基础组件后,会注入 redux 方便我们的状态管理

    (此章代码在ng2-admin 的 httpclient-submit 分支上,可以pull 下来,方便读者练习)

    相关文章

      网友评论

        本文标题:使用ng2-admin搭建成熟可靠的后台系统 -- ng2-ad

        本文链接:https://www.haomeiwen.com/subject/lslhnxtx.html