One of my goals with DataTables 1.10 was to have it support external helper libraries such as Knockout. I've just put together a little demo showing DataTables using Knockout - rows are added to the table and removed automatically as the contents of the `observableArray` are altered, and the cells for existing items as their values are changed.

http://datatables.net/dev/knockout/

This makes use of the observable aspect of Knockout only, not templates as well.

This is my first effort of using Knockout, so I'm reaching out to all the Knockout experts out there. Firstly, what do you think, and secondly how can it be improved?

Replies

One of the downsides I see to the approach of having the subscriptions in each row's data update the table is that you don't really keep a separation between your data and how it gets presented. In how we've been implementing things, our data models get used for multiple purposes (and the parts of the same model may even be present in multiple tables).

Here's an example of some patterns we follow on a pretty regular basis with 1.9:

- In a fnCreatedRow callback, apply a binding of the model to the row something like the following:
[code]
var fnCreatedRow = function(nRow, customer) {
// When clicking on a row, toggle whether or not it is selected
// (Note that things outside of the table can change which customer is selected and the customer selected may not even be one that is represented in this particular table)
$(nRow).attr("data-bind", "click: toggleSelected, css: { rowSelected: selected() }");
ko.applyBindings(data, nRow);
};
[/code]

Thanks for the comments! What I was hoping to achieve with my demo was a separation between DataTables and Knockout. Not sure I really achieved that, since there needs to be invalidation, but DataTables already does a lot of what the templating could - which is why I didn't use either the tempting of fnCreatedRow - there just wasn't any need to.

It seems to be a bit of a trade-off since DataTables and Knockout can overlap a little bit, but I'm very interested to hear from yourself and anyone else on how I can improve this situation. I suspect we'll end up with multiple possible ways of combining the libraries.

Its the library that most people have asked about for integration with DataTables, in this category of library. The other one is Backbone.

My using Knockout here shouldn't be seen as me endorsing Knockout over any other library - as I said above, its my first use of Knockout. Ultimately it would be nice to support more of these libraries in DataTables - but I had to start somewhere.

I don't really want this conversation to be sidetracked into the pros and cons of each library - this is specifically about Knockout. I'm sure it would be possible to integrate CANJS as well - if you want to let others know how you get on with it, a new thread would be great.

Something similar to the following might work to setup the link between observables and invalidate in the column definition, but would need to be able to directly reference the table:
[code]
// Code for defining a column
{
data: 'first()',
fnCreatedCell: function(nTd, sData, oData, iRow, iCol) {
sData.first.subscribe(function(val) {
dt.row( iRow ).invalidate();
});
}
}
[/code]

As noted 1.10 is pre-beta at the moment, so I don't want those unwary few falling into the trap of thinking it is suitable for production - its not! I also don't want to spend time explaining aspects of 1.10 which will be documented - once the documentation is written. I'd rather spend the time writing the documentation and get it all out sooner!

A beta will be released once documentation has been written, at which point a dedicated download will be made available.

Does .fnGetData() still work? I am new to datatables so excuse my inquiry if it's very basic and I am missing something. I am having trouble getting access to the underlying data object in the ko viewmodel when using the KO support in datatables. How do we access the underlying data object of a row by the index? Thank you.

Yes it should - although encourage use of the new API (which is difficult since its undocumented yet I acknowledge). `row( select ).data()` will get you the data for a row, while `rows().data()` will get the data for all rows.

Thank you, that is working better than .fnGetData(). However I am trying to get the selected row index and am getting the error "TypeError: Object # has no method 'fnGetPosition'" when trying to use .fnGetPosition(). I believe this is the error that I also received when attempting to use .fnGetData(). Is there more of this undocumented API to be had and get the row index?

Could you open a new thread if you have any other questions about 1.10 which are not specifically about my Knockout example? We've deviated from the topic a little :-). More than happy to answer your questions - I was just hoping to get a bit more feedback about the Knockout integration in this thread.

Thank you very much for your help. That is working great now. So I would have to say that the KO integration is working pretty good so far, but I will continue to work up this example I have started and let you know if I run into anything KO specific. Thanks again.

> The real question might be: What is the difference between .dataTable() and .DataTable()?

That's the key!

`.dataTable()` returns a chained jQuery object (so your `table` elements in a jQuery object). While `.DataTable()` returns a DataTables API object. You can use `.dataTable().api()` to also get an API instance.

This will be explained properly in the documentation that is yet to be written :-)

Thanks again allan. Where is the appropriate place to report potential bug findings for the 1.10 beta? I have found that if the sort is set programmatically like "$('#example').dataTable().fnSort( [ [0,'desc'] ] );" that it breaks subsequent sorting through the actual table headers of the DataTable.

Thanks for flagging that error - that's one I knew about and had hoped to fix today, but the day has rather run away with me... There are a couple of errors in the API helper functions not calling correctly as well.

Hi Allan.
I have created binding handler for knockout that I based on datatables 1.10: https://gist.github.com/rosieks/8812216

Main advantage of it over your solution is except it use knockout model, it also use knockout data binding. This provide ability to create rich template for column, take advantage of Chrome knockout debugger, etc. Unfortunately I need to use private function _fnAjaxUpdateDraw (https://gist.github.com/rosieks/8812216#file-knockout-datatables-js-L166) in order to pass data from model to table. Could you advice me if is there any better way to do that?

Very nice - thanks for sharing this with us! I don't think there is a better way of working around the fact that _fnAjaxUpdateDraw is private at the moment. I had always assumed that the callback in fnServerData would be enough for the public interface, but that assumption (as so many are!) was incorrect it seems...

One thing about calling _fnAjaxUpdateDraw - I think you need to pass the table's settings object into `_fnAjaxUpdateDraw ` as the first parameter.

I'm brand new to DataTables. I'm not a Knockout expert, but I've been using it for about a year and have created some complex bindingHandlers. (There are definitely people more savy with Knockout than I am.) That being said, I think something like this would fit better into a Knockout project: