我正在使用针对DataTables的敲除绑定suggested here。但是,当使用FixedColumns扩展(将原始数据表克隆到新数据表)时,我丢失新数据表与现有 viewmodel / bindingContext 之间的绑定。
例如,在固定列上选择复选框以从表中选择项目将不会按预期运行。
绑定看起来像这样:
ko.bindingHandlers.dataTablesForEach = {
page: 0,
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var binding = ko.utils.unwrapObservable(valueAccessor());
if (binding.options.paging) {
binding.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 binding = ko.utils.unwrapObservable(valueAccessor()),
key = 'DataTablesForEach_Initialized';
var table;
if (!binding.options.paging) {
table = $(element).closest('table').DataTable();
table.destroy();
}
ko.bindingHandlers.foreach.update(element, valueAccessor, allBindings, viewModel, bindingContext);
table = $(element).closest('table').DataTable(binding.options);
if (binding.options.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) && (binding.data || binding.length)) {
ko.utils.domData.set(element, key, true);
}
return {
controlsDescendantBindings: true
};
}
答案 0 :(得分:1)
我还想补充一点,因为固定列,你不会丢失绑定。绑定仍然存在。这只是插件创建的新html浮动在原始绑定的html之上。
然而,我做了这个黑客工作......在调用applybindings后添加此内容...
编辑:需要将事件绑定到文档,因为固定列插件会根据页面动态重写元素。
$(document).on('click','.DTFC_LeftBodyWrapper input[type="checkbox"]',function(){
var value = $(this).attr('value');
$('.dataTables_scrollBody').find('input[value="'+value+'"]').click(); });
我想如果你不能绑定克隆的html,那么你可以强制它与原始的html进行交互......它真的很hacky但它的工作原理..¯_(ツ)_ /¯
答案 1 :(得分:0)
我最终得到了一个绑定,它在创建后将克隆表重新应用于克隆表(即固定列表):
import $ from 'jquery';
import ko from 'knockout';
import 'datatables.net';
import 'datatables.net-fixedColumns';
const defaultOptions = {
deferRender: true,
paging: true
};
ko.bindingHandlers.datatables = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
const $element = $(element),
binding = ko.unwrap(valueAccessor()),
options = binding.options || {};
$.extend(true, options, defaultOptions);
if (binding.rowTemplateId && binding.data) {
// bind the header first
ko.applyBindingsToDescendants(viewModel, $element.find('thead')[0]);
setupTableBody($element, binding, bindingContext);
if (ko.isObservable(binding.data)) {
// destroy and build the table again when the data changes
binding.data.subscribe(() => {
$element.DataTable().destroy();
$element.find('tbody').remove();
setupTableBody($element, binding, bindingContext);
initializeDataTable(element, options);
}, null, 'arrayChange');
}
}
initializeDataTable(element, options);
ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
$(element).DataTable().destroy();
});
return {
controlsDescendantBindings: true
};
}
};
function initializeDataTable(element, options) {
const table = $(element).DataTable(options);
if (options.fixedColumns) {
// we need to apply the context to the cloned table for the first time
setTimeout(() => {
applyBindingsToClonedRows(element, options.fixedColumns);
}, 0);
// register handler to fix the cloned table column width
// when the table is (re)drawn
table.on('draw.dt', (event) => {
$(event.target).DataTable().fixedColumns().relayout();
});
// register handler to fix the cloned table binding context
// when the table is (re)drawn
table.on('draw.dt.DTFC', (event) => {
applyBindingsToClonedRows(event.target, options.fixedColumns);
});
}
}
function setupTableBody($element, binding, bindingContext) {
// render each element of the body with the template
let tbody = $element.find('tbody')[0];
if (!tbody) {
tbody = document.createElement('tbody');
$element.append(tbody);
}
ko.renderTemplateForEach(ko.unwrap(binding.rowTemplateId), binding.data, {}, tbody, bindingContext);
}
function applyBindingsToClonedRows(originalTable, fixedColumnsOptions) {
const $table = $(originalTable);
const rows = $table.find('tbody>tr');
if (fixedColumnsOptions.leftColumns) {
const clonedRows = $table.parent().parent().parent().find('.DTFC_LeftBodyWrapper .DTFC_Cloned').find('tbody>tr');
for (let i = 0; i < rows.length; i++) {
ko.applyBindings(ko.contextFor(rows[i]), clonedRows[i]);
}
}
if (fixedColumnsOptions.rightColumns) {
const clonedRows = $table.parent().parent().parent().find('.DTFC_RightBodyWrapper .DTFC_Cloned').find('tbody>tr');
for (let i = 0; i < rows.length; i++) {
ko.applyBindings(ko.contextFor(rows[i]), clonedRows[i]);
}
}
}
我创建了一个github repo,其中也包含一些示例,因为它可能会帮助其他人。
如果您觉得这个回答了问题,请投票,我会将其标记为答案 - 它肯定会回答我最初的问题,但我会很感激一些反馈。
请注意,这是ES2015代码,因此您需要进行转换。