我正在尝试进行自定义绑定以允许knockout与jquery datatables插件一起使用,我有一个有趣的问题。绑定本身并不是问题,它是数据表工作方式引起的问题。
以下是该方案:
数据和元素都通过自定义的敲除绑定绑定在一起。一切都按预期工作,除非修改了一个可观察的视图模型对象,但该对象所绑定的html元素当前不在页面上。这是怎么发生的?那么当您为分页配置了数据表并且您在单个页面上有更多项目时,数据表只会将该页面中存在的元素放入DOM中。当您浏览页面时,它会交换出html元素。
因此,如果您修改了一个可观察对象,并且该对象与datatables对象的不同页面上的html元素相关联,那么从对象到html元素的绑定将不再起作用。如果在视图中更改html元素,它可以工作。该值将被推送到对象。但是,一旦修改了对象并且html元素不在视图中,您就不能再修改该对象并将值推送到html元素。
我相信这是因为当可观察对象将值推送到html元素并且它不存在时,它无法重新订阅html元素,因此它不再能发送通知。
我想要做的是在DataTables控件中进行绘制回调,该控件查看数据和html元素并确定该订阅是否已损坏。这将允许我修复损坏的订阅,因为在用户分页时换出行。是否可以确定订阅是否被破坏并使用淘汰API“修复它”。
我的问题是关于淘汰而不是jquery datatables插件以及我正在尝试做什么。我只是认为有必要为observable更新时某个元素可能丢失的原因提供上下文。
任何帮助都将不胜感激!!
更新 使用下面的答案,我确实解决了我的问题,但没有像我希望的那样有效,因为我仍然没有办法检测订阅是否被破坏。现在我只删除绑定并在DataTable页面时重新应用它们:
rowCallback: function (row, data, index) {
var koContext = ko.contextFor(row);
ko.cleanNode(row);
ko.applyBindings(koContext, row);
}
**更新2 ** 对于每个可能遇到这种情况的人来说,我创建了完整的绑定
/*
* Knockout Binding that allows for the developer to generate content in a datatable
* that is bound to view model objects via knockout. Based on: https://github.com/zachpainter77/DatatablesForEach-Custom-Knockout-Binding
*/
ko.bindingHandlers.dtForeach = {
page: 0,
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var options = ko.unwrap(valueAccessor());
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, options.data, allBindings, viewModel, bindingContext);
},
update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var options = ko.unwrap(valueAccessor()), key = 'DataTablesForEach_Initialized';
var dtData = ko.unwrap(options.data);
var dtOptions = ko.unwrap(options.dataTableOptions);
var tableElement = $(element).closest('table');
/*
* Destroy old table and reinitialize it with
* new data
*/
var table = tableElement.DataTable();
if (dtOptions !== undefined && dtOptions.paging) {
ko.bindingHandlers.dtForeach.page = table.page();
}
table.destroy();
ko.bindingHandlers.foreach.update(element, options.data, allBindings, viewModel, bindingContext);
var bdtOptions = ko.bindingHandlers.dtForeach.setupOptions(dtOptions);
table = tableElement.DataTable(bdtOptions);
if (bdtOptions.paging) {
if (table.page.info().pages - ko.bindingHandlers.dtForeach.page == 0)
table.page(--ko.bindingHandlers.dtForeach.page).draw(false);
else
table.page(ko.bindingHandlers.dtForeach.page).draw(false);
}
if (!ko.utils.domData.get(element, key) && (options.data || options.length))
ko.utils.domData.set(element, key, true);
return { controlsDescendantBindings: true };
},
setupOptions: function (options) {
/*
* Make a deep copy of options because DataTables code
* sometimes changes settings and we want to make some modifications for
* this binding
*/
var bdtOptions = {};
if (options !== undefined)
$.extend(true, bdtOptions, options);
/*
* Need to register a row callback so that bindings are maintained
* for rows that are not visible when paging
*/
if (bdtOptions.paging) {
bdtOptions.rowCallback = function (row, data, index) {
var koContext = ko.contextFor(row);
ko.cleanNode(row);
ko.applyBindings(koContext, row);
}
}
return bdtOptions;
}
};
答案 0 :(得分:0)
这可能有所帮助:How to clear/remove observable bindings in Knockout.js? 您可以在页面的所有元素离开数据表视图之前删除绑定,当新页面出现时,将JS视图模型绑定到其元素。
为此,您需要在JS代码中跟踪当前显示哪些元素,以便将它们绑定到视图。