我正在尝试使用DataTable对项目列表执行回调以进行分页。现在我想在渲染每个项目之后渲染所有项目之后执行我的回调。在SO question之后我创建了简单的自定义绑定
ko.bindingHandlers.ConvertToDataTable = {
update: function (element, valueAccessor, allBindings) {
var list = ko.utils.unwrapObservable(valueAccessor()); //grab a dependency to the obs array
var tableId = allBindings().tableId;
$('#' + tableId).dataTable({
"sDom": "<'row'<'span6'l><'span6'f>r>t<'row'<'span6'i><'span6'p>>"
});
}
}
我的观点是:
<table class="table table-striped table-bordered" data-bind="attr: { id: tableId }">
<thead>
<tr>
<td>Task Name</td>
<td>Task Description</td>
</tr>
</thead>
<tbody>
<!-- ko foreach: tasks, ConvertToDataTable: tasks, tableId: tableId -->
<tr>
<td data-bind="text: Name"></td>
<td data-bind="text: Details"></td>
</tr>
<!-- /ko -->
</tbody>
</table>
该代码工作正常,但项目数量较少。但是,如果我的物品完全被重新剔除,则需要大量的记录(例如500)自定义绑定。任何想法?
更新
我通过AJAX从服务器获取数据,所以当我的可观察数组items
为空时,可能首先执行自定义绑定
答案 0 :(得分:3)
从逻辑的角度来看,ConvertToDataTable
绑定不应该放在桌子本身上,而应放在foreach
上吗?
另外,您是不是应该通过绑定或视图模型来控制表格布局?对于硬编码值,自定义绑定是一个非常糟糕的地方。
无论如何,controlsDescendantBindings
是你的朋友(docs):
自定义绑定:
ko.bindingHandlers.dataTable = {
init: function () {
return { controlsDescendantBindings: true };
},
update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var layout = valueAccessor();
ko.applyBindingsToDescendants(bindingContext, element);
$(element).dataTable({ "sDom": layout });
}
};
查看型号:
{
dataTableLayout: "<'row'<'span6'l><'span6'f>r>t<'row'<'span6'i><'span6'p>>",
tasks: ko.observableArray([/* ... */])
}
模板:
<table data-bind="dataTable: dataTableLayout">
<thead>
<tr>
<td>Task Name</td>
<td>Task Description</td>
</tr>
</thead>
<tbody data-bind="foreach: tasks">
<tr>
<td data-bind="text: Name"></td>
<td data-bind="text: Details"></td>
</tr>
</tbody>
</table>
免责声明:我不确切知道jQuery DataTables是如何工作的,因此样本是空中代码。我想说的是,如果需要,你可以手动控制绑定。
答案 1 :(得分:1)
这是我使用的自定义绑定!这包括您要在绑定中定义的所有数据表选项...
ko.bindingHandlers.dataTablesForEach = {
page: 0,
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var options = ko.unwrap(valueAccessor());
ko.unwrap(options.data);
if(options.dataTableOptions.paging){
valueAccessor().data.subscribe(function (changes) {
var table = $(element).closest('table').DataTable();
ko.bindingHandlers.dataTablesForEach.page = table.page();
table.destroy();
}, null, 'arrayChange');
}
var nodes = Array.prototype.slice.call(element.childNodes, 0);
ko.utils.arrayForEach(nodes, function (node) {
if (node && node.nodeType !== 1) {
node.parentNode.removeChild(node);
}
});
return ko.bindingHandlers.foreach.init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
},
update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var options = ko.unwrap(valueAccessor()),
key = 'DataTablesForEach_Initialized';
ko.unwrap(options.data);
var table;
if(!options.dataTableOptions.paging){
table = $(element).closest('table').DataTable();
table.destroy();
}
ko.bindingHandlers.foreach.update(element, valueAccessor, allBindings, viewModel, bindingContext);
table = $(element).closest('table').DataTable(options.dataTableOptions);
if (options.dataTableOptions.paging) {
if (table.page.info().pages - ko.bindingHandlers.dataTablesForEach.page == 0)
table.page(--ko.bindingHandlers.dataTablesForEach.page).draw(false);
else
table.page(ko.bindingHandlers.dataTablesForEach.page).draw(false);
}
if (!ko.utils.domData.get(element, key) && (options.data || options.length))
ko.utils.domData.set(element, key, true);
return { controlsDescendantBindings: true };
}
};