Angular Datatable的一些问题
这几天改bug中发现的一些问题,小结一下。从简单到复杂逐个讲。
angular datatable实质上是对jquery库的包装,但包装后不太好用,定制功能比较麻烦。
1. 基本用法
最简单的用法,大致就是template里:
<table datatable [dtOptions]="dtOptions">
component里:
dtOptions: DataTables.Settings;
最基本的就这两句,其他代码都不用改,table就自然有了搜索,按列排序等功能。
2. css
如果要用分页功能,一是dtOptions需配置一下:
dtOptions: DataTables.Settings = {paging: true};
二是需要在angular.json里加上css路径,不然分页栏排版错乱:
"styles": [
"node_modules/datatables.net-dt/css/jquery.dataTables.css",
3. 去掉(不显示)上方每页显示N条记录的下拉选择框
dtOptions配置:
dtOptions: DataTables.Settings = {lengthChange: false;}
4.避免和已有的css冲突
原来的table已经定义了一套css,加上datatable属性后,原有的css被破坏了。我用个笨办法,手工把上面那个jquery.dataTables.css的内容拷到另外一个文件,然后注释掉不需要的部分后再引用。但这样做了之后,发现表头和表体各列还是对不齐,最后发现还是要配置dtOptions:
dtOptions: DataTables.Settings = {autoWidth: false;}
5. 数据刷新的问题
这个折腾了不少时间。开始用dtTrigger,即template里:
<table datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger">
component里:
dtTrigger: Subject<any> = new Subject<any>();
this.someWebservice.someMethod().subscribe(data => {
...
this.dtTrigger.next();
});
问题是刷新数据时就会提示datatable不能再次初始,比较简单的解决方法是配置一下dtOptions:
dtOptions: DataTables.Settings = { destroy: true};
这样设置后,不再报错。问题是按列排序时,发现数据没有刷新,还是用的老数据。试了不少方法都不行,最后只能把table放在ViewChild里,在父部件里传数据,这样dtTrigger就不需要了。
6. 排序问题
1)日期列排序不正确,解决办法就是设置dtOptions:
dtOptions: DataTables.Settings = {"columnDefs": [{ "targets": [5, 6], "type": "date" }]};
2) 有一个列,是金钱类型,本来没什么,但是它有个特殊的格式,凡是负数,不显示负号,而是用括号来表示,如($5.00)。这样一来,缺省的排序就出错了。花了不少时间,最后发现解决办法是利用dtOptions的render属性:
dtOptions: DataTables.Settings = {"columnDefs": [{ "targets": [9, 10], "render": (data, type, row) => {
if (type == 'display') {
return this.minusSignPipe.transform(this.currencyPipe.transform(data));
}
return Number(data);
}]};
上面的currencyPipe是angular自带的,minusSignPipe是我们自己写的,把负号转成括号。
3) 学会了上面render的用法,解决了几个列的排序问题,但最后有两个列,用这个方法无法解决。这个列的html代码是:
<td><a href="javascript:void(0)" (click)="foo(row.id)" *ngIf="row?.bar> 0">{{row?.bar | currency | minusSignPipe}}</a></td>
如果用render,排序是解决了,问题是点击无反应,无法触发component里的foo()方法。花了不少时间,最后想到利用javascript变通实现:
<td><a href="javascript:void(0)" onclick="document.getElementById('btnFoo').click();" *ngIf="row?.bar > 0">
{{row?.bar | currency | minusSignPipe}}</a></td>
<button id="btnFoo" style="display:none" (click)="foo(row.id)">foo</button>
也即利用一个隐藏的button中转一下,成功触发foo()方法。因为onclick里不能用{{row?.id}}的方式传参数,所以只能用变通的方法中转。之所以用button的click事件,是因为foo()方法里需要将一个事件emit出去,触发父部件里的方法:
@Output() emitter = new EventEmitter();
foo(id) {
this.emitter.emit(id);
}
另外一个列也需要传递参数,不过不需要emit,稍微变通了一下,这样解决:
<td><a href="javascript:void(0)" onclick="window.foo(this.nextSibling.value);" *ngIf="row?.bar && row?.bar != 0">
{{row?.bar | currency | minusSignPipe}}</a><input type="hidden" value="{{row?.id}}" style="width:1px" /></td>
component里:
constructor(
) {
window['foo'] = (id) => {
this.bar(id);
};
}
这个方法不能用于有emit的情况,虽然可以触发方法,但无法emit出去。
7. drawCallback的应用
dtOptions里有个drawCallback属性,在排序等操作后会触发。利用这一特性,解决了一个问题,就是将单数行和双数行用不同的颜色显示。开始以为用css就可以了,但发现class="odd"和class="even"经常出现错乱,极不可靠,特别是排序之后。最后只能用drawCallback。
dtOptions: DataTables.Settings = {drawCallback: (settings) => {
let nodes = settings.nTBody.childNodes;
let count = 0;
if (settings.aoData[0] != undefined) {
for (let i = 0; i < nodes.length; i++) {
if (nodes[i].nodeName == "TR" && nodes[i].hasChildNodes() == true) {
if (count % 2 == 0) {
nodes[i].firstChild.parentElement.outerHTML = nodes[i].firstChild.parentElement.outerHTML.replace(/style="background-color:white"/gi, 'style="background-color:#9ddbf2"');
}
else {
nodes[i].firstChild.parentElement.outerHTML = nodes[i].firstChild.parentElement.outerHTML.replace(/style="background-color:#9ddbf2"/gi, 'style="background-color:white"');
}
count = count + 1;
}
}
}
}
}};
后来发现这个方法在IE上无效,Chrome可以,因为需要通过WebBrowser控件访问,只好另外想了个麻烦的方法。template里:
<td><span style="display:none;width:1px">{{row?.serial}}</span>{{row?.id}}</td>
这个隐藏的serial相当于数据列表的索引项,在component里另外用一个数组来保存数据行的顺序:
rows = [];
dataList = []; this.someWebService.someMethod().subscribe(data => {
let count = 1;
dataList = data;
for (let i = 0; i < dataList.length; i++) {
dataList[i].serial = count;
rows.push(count);
count++;
}
});
然后在drawCallback里给rows数组重新赋值:
dtOptions: DataTables.Settings = {drawCallback: (settings) => {
let nodes = settings.nTBody.childNodes;
let count = 0;
if (settings.aoData[0] != undefined) {
for (let i = 0; i < nodes.length; i++) {
if (nodes[i].nodeName == "TR" && nodes[i].hasChildNodes() == true) {
let str = nodes[i].firstChild.parentElement.outerHTML.toString();
this.rows[count] = parseInt(nodes[i].firstChild.firstChild.textContent);
count = count + 1;
}
}
}
}};
然后在template里绑定一个方法读取rows数组:
<td [style.background-color]="getRowStyle(row)"><span style="display:none;width:1px">{{row?.serial}}</span>{{row?.id}}</td>
getRowStyle方法:
getRowStyle(row: Foo) {
for (let i = 0; i < this.rows.length; i++) {
if (this.rows[i] == row.serial) {
if (i % 2 == 0) {
return "white";
}
else {
return "#9ddbf2";
}
}
}
}
方法是比较笨,但一时也想不出好办法。不过从中也体会到一些drawCallback的应用。
Angular Datatable的一些问题的更多相关文章
- angular JS中使用jquery datatable 自定义搜索按钮点击事件 和mRender的 ng-click事件
'use strict'; app.controller('DataTableCtrl', function ($scope, $compile) { $scope.searchFiles = { n ...
- angular JS中使用jquery datatable添加checkbox点击事件
'use strict'; app.controller('DataTableCtrl', function ($scope, $compile) { $scope.selected = []; $s ...
- angular JS中使用jquery datatable添加ng-click事件
'use strict'; app.controller('DataTableCtrl', function ($scope, $compile) { $scope.show = function ( ...
- angular.js的表格指令
html div.col-sm-12 table.table.table-bordered.table-condensed.table-hover.table-striped.dataTable.no ...
- 集腋成裘-05-angularJS -初识angular
私以为angular的最大特点是:只关注数据 1.1 angular之:双向绑定 <!DOCTYPE html> <html ng-app=""> < ...
- 【转】Angular学习总结--很详细的教程
*这篇文章是转来的,做了自己的一点修改,排版.原始出处不明,如涉及原博主版权问题,请及时告知,我将会立即删除*. 1 前言 前端技术的发展是如此之快,各种优秀技术.优秀框架的出现简直让人目不暇接,紧跟 ...
- angular.js前端分层开发(页面和js代码分离,并将js代码分层)
一. 抽取模块成base.js文件// 定义模块: var app = angular.module("eshop",['pagination']); 二. 抽取服务成brandS ...
- 增删改查列表angular.js页面实现
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...
- Angular.js实现分页
一.编写angularJS实现的分页js(网上搜)和样式表(pagination),并在页面引入 二.编写变量和方法 //分页控件控制 $scope.paginationConf={ currentP ...
随机推荐
- C++语法小记---函数对象
函数对象 用于替代函数指针 优势:函数对象内部可以保存状态,而不必使用全局变量或静态局部变量 关键:重载"()"操作符 #include<iostream> #incl ...
- 更改docker默认存储路径操作(centos6版本)
一. centos6版本 service启动方式 1.更改启动文件 vim /etc/sysconfig/docker 添加更改的路径 '--graph="/data/docker&q ...
- 深入剖析.NETCORE中CORS(跨站资源共享)
前言 由于现代互联网的飞速发展,我们在开发现代 Web 应用程序中,经常需要考虑多种类型的客户端访问服务的情况:而这种情况放在15年前几乎是不可想象的,在那个时代,我们更多的是考虑怎么把网页快速友好的 ...
- emacs org-mode 中文手册精简版(纯小白)
一只小白看了大佬的讲解视频结合其他大佬给整理的笔记再结合emacs 官方英文手册,觉得自己的知识好像增加了. 当时自己在全网搜索的时候没有看到那种纯小白的手册,本小白就写了这个,就当奉献社会了.若有不 ...
- 字节数组X中存放着 0~F共16个十六进制数,请将这些数以十六进制形式显示在屏幕上。
问题 字节数组X中存放着 0~F共16个十六进制数,请将这些数以十六进制形式显示在屏幕上. 代码 data segment x db 0,1,2,3,4,5,6,7,8,9,0ah,0bh,0eh,0 ...
- PHP sqrt() 函数
实例 返回不同数的平方根: <?phpecho(sqrt(0) . "<br>");echo(sqrt(1) . "<br>"); ...
- 下载excel模板,导入数据时需要用到
页面代码: <form id="form1" enctype="multipart/form-data"> <div style=" ...
- intel:spectre&Meltdown侧信道攻击(二)
上面一篇介绍了spectre&meltdown基本原理和简单的demo方案,今天继续学习一下该漏洞发现团队原始的POC:https://spectreattack.com/spectre.pd ...
- 【NOI2005】聪聪与可可 题解(最短路+期望DP)
前言:学长讲的太神了:自己还能推出来DP式子,挺开心. -------------------------- 题目链接 题目大意:给定一张含有$n$个结点$m$条边的无向连通图.现在聪聪在点$s$,可 ...
- SLAM中的逆深度参数化
参数化问题 在SLAM的建图过程中,把像素深度假设成了高斯分布.那么这么假设是否是合适的呢?这里关系到一个参数化的问题. 我们经常用一个点的世界坐标x,y,z三个量来描述它,这是一种参数化形式.我们认 ...