使用ng2-admin搭建成熟可靠的後臺系統 -- ng2-admin(六)

使用ng2-admin搭建成熟可靠的後臺系統 -- ng2-admin(六)

完善動態表單組件

先來張本章節最終效果圖
markcss

  • 抽離公共項,優化引入方式
  • 添加樣式,使咱們的項目更加美觀
  • 建立動態表格組件
  • 配置頁面生成文件,自動化生成

抽離公共項,優化引入方式

重複的代碼就是失敗的代碼,因此寫代碼也是一個持續優化的過程。

咱們須要用到增刪改查,上一章利用 dynamic-form.service.ts 完成了「增」的操做,如今利用一樣的文件,完成咱們的查詢工做,既然用到同一個服務,因此咱們須要把文件抽離,讓它更像一個公共文件。html

dynamic-form/dyanmic-form.service.ts -> api/http/dynamic.service.tsnode

import { Observable } from 'rxjs/Observable';
import '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 DynamicService {
  constructor(
    private http: HttpClient,
    private https: HttpComponentUtil,
    private handleService: HandleService
  ) {}

  public getList(url: string, params: {} = {}): Observable<any> {
    let api_url: string = this.https.getUrl(url);
    return this.http.get(api_url, params)
    .map((res: any) => (<any>this.handleService.handleStatus(res)).value || undefined)
    .catch(err => this.handleService.handleError(err));
  }

  /**
   *
   *
   * @param {string} url
   * @param {{}} [params={}] 請求入參的 body,參數
   * @returns {Observable<any>}  返回一個可供訂閱的觀察者對象
   * @memberof DynamicService
   *
   *
   */
  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)); // 捕獲系統錯誤
  }
}

如上述代碼,同時添加一個 getList 方法,讓它有了查詢的功能,如今還須要作兩件事情,先思考一下git

  • api/index.ts 導出這個服務,使其自動注入到 PagesModule
  • 刪除原有文件 dynamic-form.service.ts 及相關信息
把時間都用在 如何找尋相對路徑 這個問題上,是很是浪費時間的一件事情

在此以前,項目的引入方式都是相對路徑,咱們如今來修改配置,而後使路徑引入變成相對路徑,這裏須要修改
tsconfig.jsongithub

...
"paths": {
  "@angular/*": ["../node_modules/@angular/*"],
  "@components/*": ["../src/app/theme/components/*"],
  "@api/*": ["../src/app/pages/api/*"]
}
...

其中有一個選項,在以前升級的過程當中已經添加,根據第一項,能夠推斷出新增的兩個選項的用途,在下面的教程中會統一使用該方式引入,在後面配置問題將再也不重複,須要讀者自行添加。
注意:在配置完成後,須要從新啓動項目使配置生效。npm

添加樣式,使咱們的項目更加美觀

好看的網頁離不開優秀的設計,咱們須要盡咱們所能,優化頁面的樣式。

在此以前,項目尚未重置過樣式,因此咱們須要去優化一下咱們的樣式json

npm i reset.css -D

pages.component.tsapi

...
import "style-loader!reset.css";
import "style-loader!sweetalert2/dist/sweetalert2.min.css";
import "style-loader!@api/universal/style.scss";
...

@api/universal/style.scss瀏覽器

.default-style {
  h1 {
    font-size: 30px;
    font-weight: bold;
    margin-bottom: 25px;
  }
}

注意:使用 import 引入的樣式將會無差異影響到全部的樣式,因此除了公用樣式,其餘都使用 styleUrls 的方式引入app

建立動態表格組件

在修改代碼的時候,大概 60%-70% 的時間都在讀以前的代碼。

咱們須要建立一個動態表格組件,對應的咱們應該先建立一些聲明文件,做爲起步,同時也可讓本身知道本身在創造什麼,項目結構以下圖。
mark

和動態表單相似,咱們先建立
dynamic-table-base/tableItem-base.ts

export class TableBase {
  controlType: string; // 類型
  title: string; // 值,類型可選
  key: string; // 字段名
  order: number; // 排序
  constructor(
    options: {
      controlType?: string;
      title?: string;
      key?: string;
      order?: number;
    } = {}
  ) {
    // 設置各個值的默認值
    this.controlType = options.controlType || "";
    this.title = options.title || "";
    this.key = options.key || "";
    this.order = options.order || 0;
  }
}

dynamic-table-base/tableItem-text.ts

import { TableBase } from './tableItem-base';

export class TextTable extends TableBase {
    controlType = 'text';

    constructor(options: {} = {}) {
        super(options);
    }
}

dynamic-table/table-base.ts

export interface TableConfig {
  url: string;
  params?: TableParams;
}

// 請求接口的一些參數
interface TableParams {
  pageSize?: number;
  pageNumber?: number;
}

準備工做到此結束,如今準備來建立咱們的動態表格組件

開發組件時,須要考慮可擴展性

咱們的表格組件應該有展現功能,規定顯示幾列,每一列的內容應該由頁面傳入,數據來源的 url 應該也由頁面配置傳入,因此咱們會有兩個 Input 屬性。
每一行的內容,由數據內容決定,例若有三條數據,應顯示三行數據,數據由組件自身請求獲取,因此應該有一個自身的屬性用於承載數據。

export class DynamicTableComponent implements OnInit{
  @Input() config: TableConfig;
  @Input() tableControls: TableBase[];
  public tableDatas: any[];
}

在加載組件時,應該自動請求數據,組件的最終效果以下
dynamic-table.component.ts

import { Component, Input, OnInit } from '@angular/core';

import { TableConfig } from "./table-base";
import { TableBase } from "./dynamic-table-base/tableItem-base";
import { DynamicService } from "@api/http/dynamic.service";

@Component({
  selector: "dynamic-table",
  templateUrl: "./dynamic-table.component.html",
  styleUrls: ["./dynamic-table.component.scss"]
})
export class DynamicTableComponent implements OnInit{
  @Input() config: TableConfig;
  @Input() tableControls: TableBase[];
  public tableDatas: any[];

  constructor(private service: DynamicService) {}

  private getTableDatas(): void {
    this.service.getList(this.config.url, this.config.params)
      .subscribe((res: any[]) => {
        console.log(res);
        if (res.length > 0) {
          this.tableDatas = res;
        }
      })
  }

  ngOnInit(): void {
    this.getTableDatas();
  }
}

dynamic-table.component.html

<section>
  <table class="table">
    <thead class="thead-default">
      <tr>
        <th *ngFor="let tableControl of tableControls;">{{tableControl.title}}</th>
      </tr>
    </thead>
    <tbody>
      <!-- 根據數據渲染對應的行數 -->
      <tr *ngFor="let tableData of tableDatas;">
        <!-- 根據控件顯示對應的列 -->
        <td *ngFor="let tableControl of tableControls">
          <ul [ngSwitch]="tableControl.controlType">
            <!-- 顯示對應字段的值 -->
            <li *ngSwitchCase="'text'">
              {{tableData[tableControl['key']]}}
            </li>
            <!-- 顯示原始數據 -->
            <li *ngSwitchDefault>
              {{tableData | json}}
            </li>
          </ul>
        </td>
      </tr>
    </tbody>
  </table>
</section>

dynamic-table.component.scss

.table thead tr th {
  background: rgba(0,0,0,.3);
  color: #fff;
  font-size: 16px;
  border-top: none;
}

.table tbody > :first-child td {
  border-top: none;
}

這樣動態表格組件的基本樣式就完成,最後別忘了在 nga.module.ts 中註冊該組件。

注意:這裏將 service 換成了 DynamicService, 因此 form 組件的 service也須要替換,不然會報錯。

配置頁面生成文件,自動化生成

組件已經構建完成,頁面的配置和 form 組件的使用方法相似,這裏直接貼代碼

user-list.component.ts

import { Component } from '@angular/core';

import { UserListService } from './user-list.service';
import { TableBase } from '@components/dynamic-table/dynamic-table-base';
import { TableConfig } from '@components/dynamic-table/table-base';

@Component({
    selector: 'ngt-user-list',
    templateUrl: './user-list.component.html',
    providers: [ UserListService ]
})

export class UserListComponent {
  public userTableControls: TableBase[];
  public userTableConfig: TableConfig = {
    url: "user"
  };

  constructor(private service: UserListService) {
    this.userTableControls = this.service.getTableControls();
  }
}

user-list.component.html

<section class="default-style">
  <h1>
    用戶列表組件
  </h1>
  <dynamic-table [config]="userTableConfig" [tableControls]="userTableControls"></dynamic-table>
</section>

user-list/user-list.service.ts

import { Injectable } from "@angular/core";

import {
  TableBase,
  TextTable
} from "@components/dynamic-table/dynamic-table-base";

@Injectable()
export class UserListService {
  getTableControls() {
    let tableControls: TableBase[] = [
      new TextTable({
        key: "id",
        title: "ID",
        order: 0
      }),

      new TextTable({
        key: "firstName",
        title: "名稱",
        order: 1
      }),

      new TextTable({
        key: "emailAddress",
        title: "Email",
        order: 2
      }),

      new TextTable({
        key: "brave",
        title: "Brave",
        order: 3
      })
    ];

    return tableControls.sort((a, b) => a.order - b.order);
  }
}

大功告成,如今能夠打開瀏覽器,嘗試先進入新增頁面,新增一個用戶,在成功返回後,會在表格頁面查詢到本身新增的數據,這樣就完成了簡單的數據展現。

如今表格還有幾個優化的點

  • 數據過多時,須要分頁
  • 缺乏搜索功能
  • 缺乏刪除功能

在後續文章,會陸續添加這些功能!

(此章代碼在ng2-admin 的 dynamic-table 分支上,能夠pull 下來,方便讀者練習)

相關文章
相關標籤/搜索