使用ng2-admin搭建成熟可靠的后臺(tái)系統(tǒng) -- ng2-admin(六)

使用ng2-admin搭建成熟可靠的后臺(tái)系統(tǒng) -- ng2-admin(六)


完善動(dòng)態(tài)表單組件

先來(lái)張本章節(jié)最終效果圖


mark
  • 抽離公共項(xiàng)厕宗,優(yōu)化引入方式

  • 添加樣式剂娄,使我們的項(xiàng)目更加美觀

  • 創(chuàng)建動(dòng)態(tài)表格組件

  • 配置頁(yè)面生成文件翅楼,自動(dòng)化生成


抽離公共項(xiàng)蚤告,優(yōu)化引入方式

重復(fù)的代碼就是失敗的代碼旦棉,所以寫(xiě)代碼也是一個(gè)持續(xù)優(yōu)化的過(guò)程疲眷。

我們需要用到增刪改查禾蚕,上一章利用 dynamic-form.service.ts 完成了“增”的操作,現(xiàn)在利用同樣的文件狂丝,完成我們的查詢(xún)工作换淆,既然用到同一個(gè)服務(wù),所以我們需要把文件抽離几颜,讓它更像一個(gè)公共文件倍试。

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

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={}] 請(qǐng)求入?yún)⒌?body,參數(shù)
   * @returns {Observable<any>}  返回一個(gè)可供訂閱的觀察者對(duì)象
   * @memberof DynamicService
   *
   *
   */
  public saveQuery(url: string, params: {} = {}): Observable<any> {
    let api_url: string = this.https.getUrl(url); // 利用公用的 http 服務(wù)蛋哭,拼接獲取url
    return this.http.post(api_url, params, {
      headers: this.https.headers
    })
    .map((res: any) => (<any>this.handleService.handleStatus(res)).value || undefined) // 捕獲錯(cuò)誤碼
    .catch(err => this.handleService.handleError(err)); // 捕獲系統(tǒng)錯(cuò)誤
  }
}

如上述代碼易猫,同時(shí)添加一個(gè) getList 方法,讓它有了查詢(xún)的功能具壮,現(xiàn)在還需要做兩件事情,先思考一下

  • api/index.ts 導(dǎo)出這個(gè)服務(wù)哈蝇,使其自動(dòng)注入到 PagesModule
  • 刪除原有文件 dynamic-form.service.ts 及相關(guān)信息

把時(shí)間都用在 如何找尋相對(duì)路徑 這個(gè)問(wèn)題上棺妓,是非常浪費(fèi)時(shí)間的一件事情

在此之前,項(xiàng)目的引入方式都是相對(duì)路徑炮赦,我們現(xiàn)在來(lái)修改配置怜跑,然后使路徑引入變成相對(duì)路徑,這里需要修改
tsconfig.json

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

其中有一個(gè)選項(xiàng)吠勘,在之前升級(jí)的過(guò)程中已經(jīng)添加性芬,根據(jù)第一項(xiàng),可以推斷出新增的兩個(gè)選項(xiàng)的用途剧防,在下面的教程中會(huì)統(tǒng)一使用該方式引入植锉,在后面配置問(wèn)題將不再重復(fù),需要讀者自行添加峭拘。
注意:在配置完成后俊庇,需要重新啟動(dòng)項(xiàng)目使配置生效。

添加樣式鸡挠,使我們的項(xiàng)目更加美觀

好看的網(wǎng)頁(yè)離不開(kāi)優(yōu)秀的設(shè)計(jì)辉饱,我們需要盡我們所能,優(yōu)化頁(yè)面的樣式拣展。

在此之前彭沼,項(xiàng)目還沒(méi)有重置過(guò)樣式,所以我們需要去優(yōu)化一下我們的樣式

npm i reset.css -D

pages.component.ts

...
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 引入的樣式將會(huì)無(wú)差別影響到所有的樣式备埃,所以除了公用樣式姓惑,其他都使用 styleUrls 的方式引入

創(chuàng)建動(dòng)態(tài)表格組件

在修改代碼的時(shí)候褐奴,大概 60%-70% 的時(shí)間都在讀之前的代碼。

我們需要?jiǎng)?chuàng)建一個(gè)動(dòng)態(tài)表格組件挺益,對(duì)應(yīng)的我們應(yīng)該先創(chuàng)建一些聲明文件歉糜,作為起步,同時(shí)也可以讓自己知道自己在創(chuàng)造什么望众,項(xiàng)目結(jié)構(gòu)如下圖匪补。


mark

和動(dòng)態(tài)表單類(lèi)似,我們先創(chuàng)建
dynamic-table-base/tableItem-base.ts

export class TableBase {
  controlType: string; // 類(lèi)型
  title: string; // 值烂翰,類(lèi)型可選
  key: string; // 字段名
  order: number; // 排序
  constructor(
    options: {
      controlType?: string;
      title?: string;
      key?: string;
      order?: number;
    } = {}
  ) {
    // 設(shè)置各個(gè)值的默認(rèn)值
    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;
}

// 請(qǐng)求接口的一些參數(shù)
interface TableParams {
  pageSize?: number;
  pageNumber?: number;
}

準(zhǔn)備工作到此結(jié)束夯缺,現(xiàn)在準(zhǔn)備來(lái)創(chuàng)建我們的動(dòng)態(tài)表格組件

開(kāi)發(fā)組件時(shí),需要考慮可擴(kuò)展性

我們的表格組件應(yīng)該有展示功能甘耿,規(guī)定顯示幾列踊兜,每一列的內(nèi)容應(yīng)該由頁(yè)面?zhèn)魅耄瑪?shù)據(jù)來(lái)源的 url 應(yīng)該也由頁(yè)面配置傳入佳恬,所以我們會(huì)有兩個(gè) Input 屬性捏境。
每一行的內(nèi)容,由數(shù)據(jù)內(nèi)容決定毁葱,例如有三條數(shù)據(jù)垫言,應(yīng)顯示三行數(shù)據(jù),數(shù)據(jù)由組件自身請(qǐng)求獲取倾剿,所以應(yīng)該有一個(gè)自身的屬性用于承載數(shù)據(jù)筷频。

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

在加載組件時(shí),應(yīng)該自動(dòng)請(qǐng)求數(shù)據(jù)前痘,組件的最終效果如下
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>
      <!-- 根據(jù)數(shù)據(jù)渲染對(duì)應(yīng)的行數(shù) -->
      <tr *ngFor="let tableData of tableDatas;">
        <!-- 根據(jù)控件顯示對(duì)應(yīng)的列 -->
        <td *ngFor="let tableControl of tableControls">
          <ul [ngSwitch]="tableControl.controlType">
            <!-- 顯示對(duì)應(yīng)字段的值 -->
            <li *ngSwitchCase="'text'">
              {{tableData[tableControl['key']]}}
            </li>
            <!-- 顯示原始數(shù)據(jù) -->
            <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;
}

這樣動(dòng)態(tài)表格組件的基本樣式就完成凛捏,最后別忘了在 nga.module.ts 中注冊(cè)該組件。

注意:這里將 service 換成了 DynamicService芹缔, 所以 form 組件的 service也需要替換坯癣,否則會(huì)報(bào)錯(cuò)。

配置頁(yè)面生成文件乖菱,自動(dòng)化生成

組件已經(jīng)構(gòu)建完成坡锡,頁(yè)面的配置和 form 組件的使用方法類(lèi)似,這里直接貼代碼

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>
    用戶(hù)列表組件
  </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: "名稱(chēng)",
        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);
  }
}

大功告成窒所,現(xiàn)在可以打開(kāi)瀏覽器鹉勒,嘗試先進(jìn)入新增頁(yè)面,新增一個(gè)用戶(hù)吵取,在成功返回后禽额,會(huì)在表格頁(yè)面查詢(xún)到自己新增的數(shù)據(jù),這樣就完成了簡(jiǎn)單的數(shù)據(jù)展示。

現(xiàn)在表格還有幾個(gè)優(yōu)化的點(diǎn)

  • 數(shù)據(jù)過(guò)多時(shí)脯倒,需要分頁(yè)
  • 缺少搜索功能
  • 缺少刪除功能

在后續(xù)文章实辑,會(huì)陸續(xù)添加這些功能!

(此章代碼在ng2-admin 的 dynamic-table 分支上藻丢,可以pull 下來(lái)剪撬,方便讀者練習(xí))

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市悠反,隨后出現(xiàn)的幾起案子残黑,更是在濱河造成了極大的恐慌,老刑警劉巖斋否,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梨水,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡茵臭,警方通過(guò)查閱死者的電腦和手機(jī)疫诽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)旦委,“玉大人奇徒,你說(shuō)我怎么就攤上這事∮酰” “怎么了逼龟?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)追葡。 經(jīng)常有香客問(wèn)我,道長(zhǎng)奕短,這世上最難降的妖魔是什么宜肉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮翎碑,結(jié)果婚禮上谬返,老公的妹妹穿的比我還像新娘。我一直安慰自己日杈,他們只是感情好遣铝,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著莉擒,像睡著了一般酿炸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上涨冀,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天填硕,我揣著相機(jī)與錄音,去河邊找鬼。 笑死扁眯,一個(gè)胖子當(dāng)著我的面吹牛壮莹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播姻檀,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼命满,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了绣版?” 一聲冷哼從身側(cè)響起胶台,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎僵娃,沒(méi)想到半個(gè)月后概作,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡默怨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年讯榕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片匙睹。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡愚屁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出痕檬,到底是詐尸還是另有隱情霎槐,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布梦谜,位于F島的核電站丘跌,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏唁桩。R本人自食惡果不足惜闭树,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望荒澡。 院中可真熱鬧报辱,春花似錦、人聲如沸单山。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)米奸。三九已至昼接,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間悴晰,已是汗流浹背辩棒。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人一睁。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓钻弄,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親者吁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子窘俺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容