Reputation: 590
I have bound a KnockOut observableArray to a jQuery DataTable. When I dynamically add items to this array, the new items are correctly being rendered in the table, however some options of the datatable itself are not being refreshed. The pager doesn't get updated. Also the "no data available" message does not disappear.
HTML:
<table class="table table-striped" id="tblSample">
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody data-bind="foreach: List">
<tr>
<td data-bind="text: Name"></td>
</tr>
</tbody>
</table>
<button class="btn" type="button" data-bind="click: AddSample">Test</button>
Knockout model:
var Sample = function(name) {
this.Name = ko.observable(name);
};
var ViewModel = function() {
var self = this;
self.List = ko.observableArray();
self.AddSample = function() {
self.List.push(new Sample('New'));
};
};
ko.applyBindings(new ViewModel());
DOM ready:
$(document).ready(function() {
$('#tblSample').dataTable({
"sDom": "<'row'<'span6'l><'span6'f>r>t<'row'<'span6'i><'span6'p>>",
"sPaginationType": "bootstrap",
"bFilter": true,
"bLengthChange": false,
"bSort": true,
"iDisplayLength": 15,
"oLanguage": {
"sLengthMenu": "_MENU_ records per pagina"
}
});
});
Working JSFiddle: http://jsfiddle.net/PhpDk/1
Am I doing something wrong, or is this a bug?
Thanks, Nico
(edit: fixed CDN links in jsfiddle)
Upvotes: 2
Views: 4757
Reputation: 140
This is the way to do it... I have made a jsfiddle showing this:
To get this to work I had to add two callback methods to the original knockout foreach binding definition. I am currently trying to get these events into the newest version of knockout. I needed to add a beforeRenderAll and afterRenderAll callback to destroy the datatable and reinitialize the datatable after the knockouts foreach binding adds the html. This works like a charm The JSFiddle showing this has a fully editable jquery datatable bound to the ViewModel through knockout.
ko.bindingHandlers.DataTablesForEach = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
return ko.bindingHandlers.foreach.init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var value = ko.unwrap(valueAccessor()),
key = "DataTablesForEach_Initialized";
var newValue = function () {
return {
data: value.data || value,
beforeRenderAll: function(el, index, data){
if (ko.utils.domData.get(element, key)) {
$(element).closest('table').DataTable().destroy();
}
},
afterRenderAll: function (el, index, data) {
$(element).closest('table').DataTable(value.options);
}
};
};
ko.bindingHandlers.foreach.update(element, newValue, allBindingsAccessor, viewModel, bindingContext);
//if we have not previously marked this as initialized and there is currently items in the array, then cache on the element that it has been initialized
if (!ko.utils.domData.get(element, key) && (value.data || value.length)) {
ko.utils.domData.set(element, key, true);
}
return { controlsDescendantBindings: true };
}
};
Upvotes: 1
Reputation: 17554
There is a native knockout grid called KoGrid https://github.com/ericmbarnard/KoGrid
But if you really want to use Datatables there is a ready to go knockout binding for it (It works with 1.9.0 only)
I have forked that binding on Github and extended it somewhat (You can access Datables object from ViewModel to refresh, filter, sort, etc), you can find it here
https://github.com/AndersMalmgren/Knockout.Extensions
Upvotes: 2