Angular-DataTables:通过 render withPromise + angular binding + row index + groupBy 提升性能
Angular-DataTables: Boosting performance by render withPromise + angular binding + row index + groupBy
我正在使用这个库:http://l-lin.github.io/angular-datatables
一切都很好 - 我呈现 table Angular 方式 - 直到数据大到足以使性能受到影响(只有 1,000 多行)。
解决方案是使用 ajax 或 promise 进行渲染,如下所示:angular-datatables the deferRender not working
所以在过去的三天里,我一直在研究如何将下面的代码从 angular 方式转换为 promise
ANGULAR 方式
view.html
<table datatable="ng" dt-options="dtOptions" class="table table-striped table-bordered">
<thead>
<tr>
<th>No</th>
<th>Issue</th>
<th>Meeting No.</th>
<th>Department/Unit</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="(key, value) in issueList | groupBy : 'IssueId' | reverse track by $index">
<td ng-class="{read : value[0].AnswerStatus == 1}">{{$index+1}}</td>
<td>{{value[0].Issue}}</td>
<td>{{value[0].MeetingNo}}</td>
<td>
<table class="table table-striped table-bordered" cellspacing="0" width="100%">
<tbody>
<tr ng-repeat="x in value">
<td width="80%">{{x.Department}}/{{x.Unit}}</td>
<td> <a class="btn btn-default waves-effect m-b-5" ng-click="sendDetail(x.IssueId,x.UnitId)"><i class="fa fa-folder-open"></i> Show </a></td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
view.js
$scope.dtOptions =
DTOptionsBuilder.newOptions()
.withOption('stateSave', true)
.withOption('stateDuration', -1)
.withOption('deferRender', true);
$http({
method: 'GET',
url: 'http://issue.json'})
.then(function(response) {
$scope.issueList = response.data;
});
issue.json
[{
"IssueId": "1",
"MeetingNo": "1",
"Issue": "Issue title 1",
"Content": "Content 1",
"AnswerStatus": null,
"UnitId": 1,
"Unit": "Unit 1",
"DepartmentId": 1,
"Department": "Department 1"
}, {
"IssueId": "2",
"MeetingNo": "1",
"Issue": "Issue title 2",
"Content": "Content 2",
"AnswerStatus": null,
"UnitId": 5,
"Unit": "Unit 5",
"DepartmentId": 1,
"Department": "Department 1"
}, {
"IssueId": "2",
"MeetingNo": "1",
"Issue": "Issue title 2",
"Content": "Content 2",
"AnswerStatus": 1,
"UnitId": 6,
"Unit": "Unit 6",
"DepartmentId": 1,
"Department": "Department 1"
}]
下面代码是我的半路改造
承诺方式
view.html
<table datatable="" dt-options="dtOptions" dt-columns="dtColumns" class="table table-striped table-bordered">
</table>
view.js
$scope.dtOptions =
DTOptionsBuilder.fromFnPromise(function() {
var defer = $q.defer();
$http({
method: 'GET',
url: 'http://issue.json'
}).then(function(result) {
defer.resolve(result.data);
});
return defer.promise;
})
.withOption('stateSave', true)
.withOption('stateDuration', -1)
.withOption('deferRender', true); //the very reason to use promise for performance booth
$scope.dtColumns = [
DTColumnBuilder.newColumn(null).withTitle('No')
.renderWith(function(data, type, full, meta) {
return (meta.row+1);
}),
DTColumnBuilder.newColumn('Issue').withTitle('Issue'),
DTColumnBuilder.newColumn('MeetingNo').withTitle('Meeting No.'),
DTColumnBuilder.newColumn('Department').withTitle('Department/Unit'),
];
如您所见,第一列缺少AnswerStatus == 1
所需的样式并且最后一列缺少Department + '/' + Unit
的组合值和导航到另一个页面的按钮。
另请注意,angular 方法正在使用 groupBy,这使我的问题更加复杂 :(
请帮忙。感谢您的宝贵时间。
更新:
其实,我也在考虑替代方案,但仍然面临障碍。
我正在考虑用这个重构 json:
Array.prototype.groupBy = function(prop) {
return this.reduce(function(groups, item) {
const val = item[prop]
groups[val] = groups[val] || []
groups[val].push(item)
return groups
}, {})
}
$scope.dtOptions =
DTOptionsBuilder
.fromFnPromise(function() {
var defer = $q.defer();
$http({
method: 'GET',
url: 'http://issue.json'
}).then(function(result) {
var d = result.data.groupBy('IssueId');
var arr = Object.values(d);
console.log(arr);
defer.resolve(arr);
});
return defer.promise;
})
.withOption('stateSave', true)
.withOption('stateDuration', -1)
.withOption('deferRender', true);
这会产生一个新的编号数组数组,如下所示 (console.log(arr)):
[
[{
"IssueId": "1",
"MeetingNo": "1",
"Issue": "Issue title 1",
"Content": "Content 1",
"AnswerStatus": null,
"UnitId": 1,
"Unit": "Unit 1",
"DepartmentId": 1,
"Department": "Department 1"
}],
[{
"IssueId": "2",
"MeetingNo": "1",
"Issue": "Issue title 2",
"Content": "Content 2",
"AnswerStatus": null,
"UnitId": 5,
"Unit": "Unit 5",
"DepartmentId": 1,
"Department": "Department 1"
}, {
"IssueId": "2",
"MeetingNo": "1",
"Issue": "Issue title 2",
"Content": "Content 2",
"AnswerStatus": 1,
"UnitId": 6,
"Unit": "Unit 6",
"DepartmentId": 1,
"Department": "Department 1"
}]
]
但我不知道如何处理新数组。
好吧,原始版本的 plunkr 在这里 http://plnkr.co/edit/Q2ob8gynNTXXId9pxnzz?p=preview
这里是重组 JSON 的方法,因此它被分组
$scope.dtOptions =
DTOptionsBuilder.fromFnPromise(function() {
var defer = $q.defer();
$http({
method: 'GET',
url: 'issues.json'
}).then(function(result) {
var data = [];
result.data.forEach(function(i) {
var item = data.find(item => item.IssueId == i.IssueId)
if (item) {
item.childs.push(i)
} else {
data.push({
IssueId: i.IssueId,
Issue: i.Issue,
MeetingNo: i.MeetingNo,
childs: [i]
})
}
})
defer.resolve(data);
})
return defer.promise;
})
这是设置列的方法
$scope.dtColumns = [
DTColumnBuilder.newColumn(null).withTitle('No')
.withOption('createdCell', function(cell, cellData, rowData, rowIndex, colIndex) {
if (rowData.AnswerStatus == 1) $(cell).addClass('read')
})
.renderWith(function(data, type, full, meta) {
return (meta.row+1);
}),
DTColumnBuilder.newColumn('Issue').withTitle('Issue'),
DTColumnBuilder.newColumn('MeetingNo').withTitle('Meeting No.'),
DTColumnBuilder.newColumn(null)
.withTitle('Department/Unit')
.renderWith(function(data, type, row, meta) {
var html = '<table><tbody>';
row.childs.forEach(function(child) {
html += '<tr><td>'+child.Department+'/'+child.Unit+'</td></tr>'
html += '<tr><td><button ng-click="buttonClick()">click</button></td></tr>'
})
html += '</tbody></table>'
return html
})
.withOption('createdCell', function(cell, cellData, rowData, rowIndex, colIndex) {
$compile(cell)($scope);
})
]
只需使用createdCell
即可post 处理列。使用 $compile
以使其他 angular 指令生效。你有一些你在原始代码中没有考虑过的问题,比如选择哪个AnswerStatus
。
我正在使用这个库:http://l-lin.github.io/angular-datatables
一切都很好 - 我呈现 table Angular 方式 - 直到数据大到足以使性能受到影响(只有 1,000 多行)。
解决方案是使用 ajax 或 promise 进行渲染,如下所示:angular-datatables the deferRender not working
所以在过去的三天里,我一直在研究如何将下面的代码从 angular 方式转换为 promise
ANGULAR 方式
view.html
<table datatable="ng" dt-options="dtOptions" class="table table-striped table-bordered">
<thead>
<tr>
<th>No</th>
<th>Issue</th>
<th>Meeting No.</th>
<th>Department/Unit</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="(key, value) in issueList | groupBy : 'IssueId' | reverse track by $index">
<td ng-class="{read : value[0].AnswerStatus == 1}">{{$index+1}}</td>
<td>{{value[0].Issue}}</td>
<td>{{value[0].MeetingNo}}</td>
<td>
<table class="table table-striped table-bordered" cellspacing="0" width="100%">
<tbody>
<tr ng-repeat="x in value">
<td width="80%">{{x.Department}}/{{x.Unit}}</td>
<td> <a class="btn btn-default waves-effect m-b-5" ng-click="sendDetail(x.IssueId,x.UnitId)"><i class="fa fa-folder-open"></i> Show </a></td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
view.js
$scope.dtOptions =
DTOptionsBuilder.newOptions()
.withOption('stateSave', true)
.withOption('stateDuration', -1)
.withOption('deferRender', true);
$http({
method: 'GET',
url: 'http://issue.json'})
.then(function(response) {
$scope.issueList = response.data;
});
issue.json
[{
"IssueId": "1",
"MeetingNo": "1",
"Issue": "Issue title 1",
"Content": "Content 1",
"AnswerStatus": null,
"UnitId": 1,
"Unit": "Unit 1",
"DepartmentId": 1,
"Department": "Department 1"
}, {
"IssueId": "2",
"MeetingNo": "1",
"Issue": "Issue title 2",
"Content": "Content 2",
"AnswerStatus": null,
"UnitId": 5,
"Unit": "Unit 5",
"DepartmentId": 1,
"Department": "Department 1"
}, {
"IssueId": "2",
"MeetingNo": "1",
"Issue": "Issue title 2",
"Content": "Content 2",
"AnswerStatus": 1,
"UnitId": 6,
"Unit": "Unit 6",
"DepartmentId": 1,
"Department": "Department 1"
}]
下面代码是我的半路改造
承诺方式
view.html
<table datatable="" dt-options="dtOptions" dt-columns="dtColumns" class="table table-striped table-bordered">
</table>
view.js
$scope.dtOptions =
DTOptionsBuilder.fromFnPromise(function() {
var defer = $q.defer();
$http({
method: 'GET',
url: 'http://issue.json'
}).then(function(result) {
defer.resolve(result.data);
});
return defer.promise;
})
.withOption('stateSave', true)
.withOption('stateDuration', -1)
.withOption('deferRender', true); //the very reason to use promise for performance booth
$scope.dtColumns = [
DTColumnBuilder.newColumn(null).withTitle('No')
.renderWith(function(data, type, full, meta) {
return (meta.row+1);
}),
DTColumnBuilder.newColumn('Issue').withTitle('Issue'),
DTColumnBuilder.newColumn('MeetingNo').withTitle('Meeting No.'),
DTColumnBuilder.newColumn('Department').withTitle('Department/Unit'),
];
如您所见,第一列缺少AnswerStatus == 1
所需的样式并且最后一列缺少Department + '/' + Unit
的组合值和导航到另一个页面的按钮。
另请注意,angular 方法正在使用 groupBy,这使我的问题更加复杂 :(
请帮忙。感谢您的宝贵时间。
更新:
其实,我也在考虑替代方案,但仍然面临障碍。 我正在考虑用这个重构 json:
Array.prototype.groupBy = function(prop) {
return this.reduce(function(groups, item) {
const val = item[prop]
groups[val] = groups[val] || []
groups[val].push(item)
return groups
}, {})
}
$scope.dtOptions =
DTOptionsBuilder
.fromFnPromise(function() {
var defer = $q.defer();
$http({
method: 'GET',
url: 'http://issue.json'
}).then(function(result) {
var d = result.data.groupBy('IssueId');
var arr = Object.values(d);
console.log(arr);
defer.resolve(arr);
});
return defer.promise;
})
.withOption('stateSave', true)
.withOption('stateDuration', -1)
.withOption('deferRender', true);
这会产生一个新的编号数组数组,如下所示 (console.log(arr)):
[
[{
"IssueId": "1",
"MeetingNo": "1",
"Issue": "Issue title 1",
"Content": "Content 1",
"AnswerStatus": null,
"UnitId": 1,
"Unit": "Unit 1",
"DepartmentId": 1,
"Department": "Department 1"
}],
[{
"IssueId": "2",
"MeetingNo": "1",
"Issue": "Issue title 2",
"Content": "Content 2",
"AnswerStatus": null,
"UnitId": 5,
"Unit": "Unit 5",
"DepartmentId": 1,
"Department": "Department 1"
}, {
"IssueId": "2",
"MeetingNo": "1",
"Issue": "Issue title 2",
"Content": "Content 2",
"AnswerStatus": 1,
"UnitId": 6,
"Unit": "Unit 6",
"DepartmentId": 1,
"Department": "Department 1"
}]
]
但我不知道如何处理新数组。
好吧,原始版本的 plunkr 在这里 http://plnkr.co/edit/Q2ob8gynNTXXId9pxnzz?p=preview
这里是重组 JSON 的方法,因此它被分组
$scope.dtOptions =
DTOptionsBuilder.fromFnPromise(function() {
var defer = $q.defer();
$http({
method: 'GET',
url: 'issues.json'
}).then(function(result) {
var data = [];
result.data.forEach(function(i) {
var item = data.find(item => item.IssueId == i.IssueId)
if (item) {
item.childs.push(i)
} else {
data.push({
IssueId: i.IssueId,
Issue: i.Issue,
MeetingNo: i.MeetingNo,
childs: [i]
})
}
})
defer.resolve(data);
})
return defer.promise;
})
这是设置列的方法
$scope.dtColumns = [
DTColumnBuilder.newColumn(null).withTitle('No')
.withOption('createdCell', function(cell, cellData, rowData, rowIndex, colIndex) {
if (rowData.AnswerStatus == 1) $(cell).addClass('read')
})
.renderWith(function(data, type, full, meta) {
return (meta.row+1);
}),
DTColumnBuilder.newColumn('Issue').withTitle('Issue'),
DTColumnBuilder.newColumn('MeetingNo').withTitle('Meeting No.'),
DTColumnBuilder.newColumn(null)
.withTitle('Department/Unit')
.renderWith(function(data, type, row, meta) {
var html = '<table><tbody>';
row.childs.forEach(function(child) {
html += '<tr><td>'+child.Department+'/'+child.Unit+'</td></tr>'
html += '<tr><td><button ng-click="buttonClick()">click</button></td></tr>'
})
html += '</tbody></table>'
return html
})
.withOption('createdCell', function(cell, cellData, rowData, rowIndex, colIndex) {
$compile(cell)($scope);
})
]
只需使用createdCell
即可post 处理列。使用 $compile
以使其他 angular 指令生效。你有一些你在原始代码中没有考虑过的问题,比如选择哪个AnswerStatus
。