使用ng2-admin搭建成熟可靠的后台系统 -- ng2-admin(六)
完善动态表单组件
先来张本章节最终效果图
- 抽离公共项,优化引入方式
- 添加样式,使我们的项目更加美观
- 创建动态表格组件
- 配置页面生成文件,自动化生成
抽离公共项,优化引入方式
重复的代码就是失败的代码,所以写代码也是一个持续优化的过程。
我们需要用到增删改查,上一章利用 dynamic-form.service.ts
完成了“增”的操作,现在利用同样的文件,完成我们的查询工作,既然用到同一个服务,所以我们需要把文件抽离,让它更像一个公共文件。
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={}] 请求入参的 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 方法,让它有了查询的功能,现在还需要做两件事情,先思考一下
- 在
api/index.ts
导出这个服务,使其自动注入到PagesModule
中 - 删除原有文件
dynamic-form.service.ts
及相关信息
把时间都用在 如何找寻相对路径 这个问题上,是非常浪费时间的一件事情
在此之前,项目的引入方式都是相对路径,我们现在来修改配置,然后使路径引入变成相对路径,这里需要修改tsconfig.json
...
"paths": {
"@angular/*": ["../node_modules/@angular/*"],
"@components/*": ["../src/app/theme/components/*"],
"@api/*": ["../src/app/pages/api/*"]
}
...
其中有一个选项,在之前升级的过程中已经添加,根据第一项,可以推断出新增的两个选项的用途,在下面的教程中会统一使用该方式引入,在后面配置问题将不再重复,需要读者自行添加。
注意:在配置完成后,需要重新启动项目使配置生效。
添加样式,使我们的项目更加美观
好看的网页离不开优秀的设计,我们需要尽我们所能,优化页面的样式。
在此之前,项目还没有重置过样式,所以我们需要去优化一下我们的样式
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 引入的样式将会无差别影响到所有的样式,所以除了公用样式,其他都使用 styleUrls 的方式引入
创建动态表格组件
在修改代码的时候,大概 60%-70% 的时间都在读之前的代码。
我们需要创建一个动态表格组件,对应的我们应该先创建一些声明文件,作为起步,同时也可以让自己知道自己在创造什么,项目结构如下图。
和动态表单类似,我们先创建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 下来,方便读者练习)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。