Datatable data binding using knockoutjs

一个人想着一个人 提交于 2019-12-04 13:20:18

I made a fiddle with a solution

http://jsfiddle.net/Jarga/hg45z9rL/

Clicking "Update" will display the current knockout model as text below the button.

What was missing was the linking the change of the textbox to the observable by adding a listener in the render function. Also each row's textbox was being given the same id, which is not a good idea either. (Note: the event aliases are just to prevent collision with other handlers)

Changing the render function to build useful ids and adding the following should work:

$('#' + id).off('change.grid')
$('#' + id).on('change.grid', function() {
    row.age($(this).val());
});

Ideally Knockout would handle this for you but since you are not calling applyBindings nor creating the data-bind attributes for the html elements all that knockout really gives you here is the observable pattern.

Edit: Additional Solution

Looking into it a little bit more you can let Knockout handle the rendering by adding the data-bindattribute into the template and binding your knockout model to the table element.

var html = '<div style="display:inline-flex">' + 
    '<input type="text" class="headerStyle h5Style" id="' + id + '" data-bind="value: $data[' + cell.row + '].age"/>'

And

ko.applyBindings(people, document.getElementById("example"));

This removes the whole custom subscription call when constructing the Personobject as well.

Here is another fiddle with the 2nd solution:

http://jsfiddle.net/Jarga/a1gedjaa/

I feel like this simplifies the solution. However, i do not know how efficient it performs nor have i tested it with paging so additional work may need to be done. With this method the mRender function is never re-executed and the DOM manipulation for the input is done entirely with knockout.

Zach Painter

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

Edit: Recently worked out a way to get this binding using vanilla knockout. I've tested this out on the latest version of knockout (3.4) Just use this binding and knockout datatables works!

ko.bindingHandlers.dataTablesForEach = {
page: 0,
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {       
    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); // !!!!! Need to set dependency     
    ko.bindingHandlers.foreach.update(element, valueAccessor, allBindings, viewModel, bindingContext);
    (function() {
        console.log(options);
        var 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

Here is a simple workaround that re-binds the data in knockout and then destroys/recreates the datatable:

// Here's my data model
var ViewModel = function() {
    this.rows = ko.observable(null);
    this.datatableinstance = null;

    this.initArray = function() {
            var rowsource1 =  [   
                    { "firstName" : "John",  
                      "lastName"  : "Doe",
                      "age"       : 23 },

                    { "firstName" : "Mary",  
                      "lastName"  : "Smith",
                      "age"       : 32 }
                  ];         
        this.redraw(rowsource1);

    }

    this.swapArray = function() {
      var rowsource2 =  [   
                      { "firstName" : "James",  
                        "lastName"  : "Doe",
                        "age"       : 23 },

                      { "firstName" : "Alice",  
                        "lastName"  : "Smith",
                        "age"       : 32 },

                      { "firstName" : "Doug",  
                        "lastName"  : "Murphy",
                        "age"       : 40 }

                    ];       
        this.redraw(rowsource2);
    }

    this.redraw = function(rowsource) {
      this.rows(rowsource);


      var options = { paging: false, "order": [[0, "desc"]], "searching":true };
      var datatablescontainer = $('#datatablescontainer');
      var html = $('#datatableshidden').html();

      //Destroy datatable
      if (this.datatableinstance) {
        this.datatableinstance.destroy();
        datatablescontainer.empty();
      }

      //Recreate datatable
      datatablescontainer.html(html);
      this.datatableinstance = datatablescontainer.find('table.datatable').DataTable(options);    
    }

};

ko.applyBindings(new ViewModel("Planet", "Earth")); // This makes Knockout get to work

https://jsfiddle.net/benjblack/xty5y9ng/

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!