0

我正在尝试对项目列表执行回调以使用DataTable进行分页。现在我想在我的所有项目都被渲染之后而不是在每个项目被渲染之后执行我的回调。在那个SO 问题之后,我创建了简单的自定义绑定

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为空时,我的自定义绑定可能首先执行

4

2 回答 2

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>

http://jsfiddle.net/WcaM5/

免责声明:我不知道 jQuery DataTables 是如何工作的,所以示例是 aircode。我想说的是,如果需要,您可以手动控制绑定。

于 2013-10-28T17:20:24.420 回答
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 };
}
};

JSFIDDLE

于 2015-12-04T22:37:24.400 回答