KnockoutJs - how to use datatables with existing b

2019-04-02 04:08发布

I have a simple HTML table which is bound using knockoutJS. However, I've added a custom binding which applies the jquery datatable plugin on the table.

When I click the headers, the table disappears. Any idea how I can get it working with knockoutJS?

2条回答
我想做一个坏孩纸
2楼-- · 2019-04-02 05:08

This is the way to do it... I have made a jsfiddle showing this:

Here is a knockout custom binding solution for jQuery datatables.

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 w/ jqueryUI

查看更多
Melony?
3楼-- · 2019-04-02 05:10

Its actually unnecessary to use knockoutJs to carry out the binding of the dataTable. As knockoutJs already binds the HTML table to the model, just use the following:

$(function() {
        var dtOptions = {
                "bPaginate": false,
                "bLengthChange": false,
                "bFilter": false,
                "bInfo": false,
                bJQueryUI: true              
        }

        var dt = $("#leadsTable").dataTable(dtOptions);

        $("#searchButton").click(function() {
           //... set url with search terms...

           $.get(url, function (data) {
                // destroy existing table
                dt.fnDestroy();

                ko.mapping.fromJS(data, vm.model);

                // re-created AFTER ko mapping
                dt.dataTable(dtOptions);                    
           });
       })
});

var serialisedModel = @Html.Raw(new JavaScriptSerializer().Serialize(Model));

var vm = {      
    data: ko.toJSON(serialisedModel),
}

ko.applyBindings(vm);

The crucial part is to destroy the existing dataTable before the mapping, and re-create after mapping. I had to keep a reference to the initial dataTable for later destroying...

查看更多
登录 后发表回答