3
votes

Im trying to render a table in knockout. The code works but as the number of rows and columns grow the rendering times become extremely long. The culprit seems to be notifying subscribers and actually performing the bindings. I'm wondering if there is a way that the table could be rendered in a way that didn't cause knockout to do so many events. This table literally has no interaction. It is purely just to display data. I was hoping to accomplish this without the need to bring in another templating engine and just use what Knockout.js has available with the data-bind attributes but I've tried and nothing seems to be satisfactory. I have two observable arrays, one for headers and one for the data. the data array is an array of arrays because I have to build out each row seperately.

<table>
  <thead>
    <tr>
      <!--ko foreach: headers -->
          <th data-bind="{'text': displayName}"></th>
      <!-- /ko -->
    </tr>
  </thead>
  <tbody data-bind="foreach: row">
    <tr class="form_row">
      <!-- ko foreach: question -->
      <!-- ko if: Type === "image" -->
      <td>
        <a data-bind="attr: {'href': $data.Value, 'target': '_blank'}">
          <img class="thumbnail-img" data-bind="  attr: {'src': $data.Value}" />
        </a>
      </td>
      <!-- /ko -->
      <!-- ko if: Type !== "image" -->
          <td data-bind="{'text': Value}"></td>
      <!-- /ko -->
      <!-- /ko -->
    </tr>
  </tbody>
</table>

You can use this JsFiddle to run something similar to my example. http://jsfiddle.net/LkqTU/27820/

1

1 Answers

5
votes

My Table binding shows how to do fast table generation with Knockout. The basic method is to construct the table using strings, and then add it all at once to the DOM using innerHTML. You could probably also use some sort of string-based template engine to do this, as described in the Knockout template documentation.

I've converted your example to use table:

<table data-bind="table: tableBinding($data)"></table>

Javascript:

vm.tableBinding = function(vm) {
    return {
        columns: vm.headers.length,
        data: vm.row,
        header: function(col) {
            return vm.headers[col].displayName;
        },
        dataItem: function(row, col, data) {
            var item = data[row].question[col],
                value = ko.utils.escape(item.Value);
            if (item.Type === "image") {
                return ko.utils.safeString('<a href="' + value + '" target="_blank"><img class="thumbnail-img" src="' + value + '" /></a>');
            } else {
                return ko.utils.safeString(value);
            }
        }
    };
};

jsFiddle: http://jsfiddle.net/mbest/b80t0cL8/