brazorf
brazorf

Reputation: 1951

KnockoutJS with jQuery Datatables and the binding plugin, row click passing the whole array instead of single model

I am using this plugin http://www.joshbuckley.co.uk/2011/07/knockout-js-datatable-bindings/ to handle datatables / ko bindings. Here's JS code:

function ProductViewModel() {
  // Init.
  var self = this;
  self.products = ko.observableArray();
  self.singleProduct = ko.observable();
  var mappedProducts;

  // At first load i'm loading data.
  $.getJSON("/admin/test", function(allData) {
    mappedProducts = $.map(allData, function(item) { 
      var p = new Product(item);
      // I'm adding a new property to my model, to handle row level actions.
      // I'm not sure this is a good practice.
      p.edit = "<button data-bind='click: $root.edit'><i class='icon-pencil'></i></button>";
      return p;
    });
    self.products(mappedProducts);
  });

  // Here i'm using the basic switch pattern, as from KO tutorials.
  self.edit = function(product) {
    console.log(product); // <--- Prints the whole self.products() array
    self.singleProduct(product);
    self.products(null);
  }

  self.list = function() {
    self.products(mappedProducts);
    self.singleProduct(null);
  }
}

// My model.
function Product(item) {
  this.name = ko.observable(item.name);
  this.dealer = ko.observable(item.dealer);
  this.cost = ko.observable(item.cost);
  this.price = ko.observable(item.price);
  this.picture = ko.observable();
}

Here's my markup:

<table id="products-table" class="table table-striped table-bordered table-hover"
             data-bind="dataTable: {data: $parent.products, options: {aoColumns: [
        { bSortable: false, mDataProp: null, sDefaultContent: '' },
        {mData: 'name'}, 
        {mData: 'dealer'},
        {mData: 'cost'},
        {mData: 'price'}, 
        { bSortable: false, mData: 'edit' }
      ]}}">
        <thead>
          <tr>
            <th>Pic</th>
            <th>Name</th>
            <th>Dealer</th>
            <th>Cost</th>
            <th>Price</th>
            <th>Actions</th>
          </tr>
        </thead>

        <tbody></tbody>
      </table>

I am able to virtually switch between list and edit views, bindings seems to be properly handled.

Problem: when in the edit handler, i would expect to receive a single model as an argument; i am receiving the whole collection though, so i am not able to identify the model to edit.

One more thing: I am not sure at all this is a good practice of binding events on the rows, so any suggestion would be appreciated!

Upvotes: 1

Views: 4073

Answers (1)

brazorf
brazorf

Reputation: 1951

Well i think i got it myself and reason is quite clear after peeking the plugin source code.

From plugin source:

(function($){
    ko.bindingHandlers.dataTable = {
        init: function(element, valueAccessor){
            var binding = ko.utils.unwrapObservable(valueAccessor());

            // If the binding is an object with an options field,
            // initialise the dataTable with those options. 
            if(binding.options){
                $(element).dataTable(binding.options);
            }
        },
        update: function(element, valueAccessor){
            var binding = ko.utils.unwrapObservable(valueAccessor());

            // If the binding isn't an object, turn it into one. 
            if(!binding.data){
                binding = { data: valueAccessor() }
            }

            // Clear table
            $(element).dataTable().fnClearTable();

            // Rebuild table from data source specified in binding
            $(element).dataTable().fnAddData(binding.data());
        }
    };
})(jQuery);

Basically, for each update operation table is cleaned up and built again with the observable array, which should provide binding features.

What KO is trying to do, in each native click: binding, is to pass in the contextual data, which is the whole array, to the proper handler.

Upvotes: 1

Related Questions