使用ng2-admin搭建成熟可靠的后臺(tái)系統(tǒng) -- ng2-admin(六)
完善動(dòng)態(tài)表單組件
先來(lái)張本章節(jié)最終效果圖
抽離公共項(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)如下圖匪补。
和動(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í))