淘汰赛3.4 - 检测订阅中断并修复

时间:2016-02-18 15:22:16

标签: knockout.js datatables

我正在尝试进行自定义绑定以允许knockout与jquery datatables插件一起使用,我有一个有趣的问题。绑定本身并不是问题,它是数据表工作方式引起的问题。

  • DataTables 1.10
  • Knockout 3.4

以下是该方案:

数据和元素都通过自定义的敲除绑定绑定在一起。一切都按预期工作,除非修改了一个可观察的视图模型对象,但该对象所绑定的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;
    }
};

1 个答案:

答案 0 :(得分:0)

这可能有所帮助:How to clear/remove observable bindings in Knockout.js? 您可以在页面的所有元素离开数据表视图之前删除绑定,当新页面出现时,将JS视图模型绑定到其元素。

为此,您需要在JS代码中跟踪当前显示哪些元素,以便将它们绑定到视图。