Knockout Table & Highlight Example

Knockout Template

HTML

<script src="https://github.com/SteveSanderson/knockout/raw/master/build/output/knockout-latest.debug.js"></script>
<script src="http://jquery-json.googlecode.com/files/jquery.json-2.2.min.js"></script>
<script src="https://raw.github.com/SteveSanderson/knockout.mapping/master/knockout.mapping.js"></script>
<table data-bind="template : { name: 'tableHeaderTmpl' , data : container.getFirst() }"></table>

<script type="text/x-jquery-template" id="tableHeaderTmpl">
  <thead>
    <tr data-bind="foreach:columns">
      <th data-bind="text:$data.title"></th>
    </tr>
  </thead>
  <tbody data-bind="template : {name:'tableBodyTmpl', foreach:rows}"></tbody>
</script>

<script type="text/x-jquery-template" id="tableBodyTmpl">
  <tr data-bind="foreach:$data">
    <td data-bind="highlight:data,text:data"></td>
  </tr>
</script>

CSS

table {
  border-collapse: separate;
  border-spacing: 1px;
  *border-collapse: expression('separate', cellSpacing='1px');
}

table,
td,
th {
  border: 1px solid black;
  text-align: center
}

th {
  background-color: black;
  color: white;
}

td {
  width: 50px;
}

JavaScript

var widgetDefinition = '{"widgets" : [ { "id":"widget1", "columns":[{"name":"QUOTE.DATETIME","title":"DATETIME"},{"name":"ASK.PRICE","title":"ASK PRICE"},{"name":"BID.PRICE","title":"BID PRICE"}] }]}';
if ($(element).data("ko_init")) {


  ko.bindingHandlers.highlight = {
    update: function(element, valueAccessor) {
      ko.toJS(valueAccessor());
      var old = parseInt($(element).html(), 10);
      var current = parseInt(valueAccessor()(), 10);
      if (current < old) {
        // $(element).clearQueue();
        $(element).css("background-color", "#AA0000");
        $(element).delay(5000).animate({
          'duration': 0,
          'backgroundColor': '#ffffff'
        });
      } else if (current >= old) {
        // $(element).clearQueue();
        $(element).css("background-color", '#00AA00');
        $(element).delay(5000).animate({
          'duration': 0,
          'backgroundColor': '#ffffff'
        });
      }

    } else {
      $(element).data("ko_init", true);
    }
  }
};

function Widget(w) {
  this.id = w.id;
  this.columns = w.columns;
  this.rows = ko.observableArray([]);
  var Cell = function(data) {
    var cellInstance = this;
    this.data = ko.observable(data);
  }
}

function WidgetContainer() {

  var self = this;

  this.widgets = new Array();

  this.addWidget = function(widget) {
    self.widgets.push(widget);
  };
  this.parseWidgets = function(definition) {
    var parsedDefinition = $.parseJSON(definition);
    ko.utils.arrayMap(parsedDefinition.widgets, function(w) {
      self.addWidget(new Widget(w));
    });
    console.log(self.widgets);
  }

  this.getFirst = function() {
    if (self.widgets.length > 0)
      return self.widgets[0];
  }

  self.parseWidgets(widgetDefinition);

}

function ViewModel() {
  var self = this;
  this.container = new WidgetContainer();

};

$(function() {

  var viewModel = new ViewModel();
  ko.applyBindings(viewModel);



  function changeData(x, y, data) {

    //...