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



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

  • 数据表 1.10
  • 淘汰赛 3.4

场景如下:

数据和元素都通过自定义挖空绑定绑定在一起。 一切都按预期工作,除非修改了可观察视图模型对象,但该对象绑定到的 html 元素当前不在页面上。 这是怎么发生的? 那么,当您为分页配置了数据表并且单个页面上的项数超过容纳范围时,数据表仅将该页数据中存在的元素放在 DOM 中。当您浏览页面时,它会交换 html 元素。

因此,如果您修改一个可观察对象,并且该对象绑定到 datatables 对象不同页面上的 html 元素,则发生的情况是从该对象到 html 元素的绑定不再有效。 如果您在视图中更改 html 元素,它就会起作用。值被推送到对象。 但是,一旦修改了对象并且 html 元素不在视图中,就无法再修改对象并将值推送到 html 元素。

我相信发生这种情况是因为当可观察对象将值推送到 html 元素并且它不存在时,它无法重新订阅 html 元素,因此它不再可以发送通知。

我想做的是在 DataTables 控件中放入一个绘制回调,该控件查看数据和 html 元素并确定该订阅是否已损坏。 这将允许我修复损坏的订阅,因为在用户分页时行被换出。 是否可以确定订阅是否已损坏并使用挖空 API "修复它"。

的问题实际上是关于淘汰而不是jquery数据表插件以及我正在尝试做什么。 我只是认为有必要提供上下文来说明为什么在可观察量更新时的某个点可能会缺少元素。

任何帮助将不胜感激!!

更新使用下面的答案,我确实解决了我的问题,但没有我希望的那样有效,因为我仍然无法检测订阅是否中断。 现在,我只是删除绑定并在数据表页面如下所示时重新应用它们:

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;
    }
};
这可能会

有所帮助: 如何在 Knockout.js 中清除/删除可观察的绑定?您可以在页面退出数据表视图之前删除页面所有元素上的绑定,当新页面进入时,将 JS 视图模型绑定到其元素。

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

最新更新