Search code examples
jqueryhtmlknockout.jsknockout-sortable

How to change row order of table using knock out. Either drag and drop or using Up/Down buttons


How do I change the row order of table using knockout. I have the fiddle:

Using knockout-sortable.js. Example

Please assist. My fiddle is below:

JSFiddle Example

  [1]:http://jsfiddle.net/rniemeyer/hw9B2/
  [2]:https://jsfiddle.net/nagarajputhiyavan/x9vc10zu/3/

Solution

  • Since the whole idea of Knockout is that you work with your data model and Knockout keeps the UI in sync with it, the fundamental problem is simply reordering your array (and it needs to be an observableArray for Knockout to notice changes to it).

    Of the two methods you suggested, the Up and Down buttons are easier, so that's what I went with. I added Up and Down buttons to each row, and disabled Up for the first row and Down for the last row.

    The Up button is click-bound to a moveUp function that splices out the current row and splices it back in a row up. The Down does the same thing, but splicing back in a row down.

    var AppModel = function() {
      var self = this;
      
      this.itemsToReceive = ko.observableArray([{
        RecordId: 1,
        IsPriority: true,
        IsInTransit: true,
        IsSpecialRecall: true
      }, {
        RecordId: 2,
        IsPriority: false,
        IsInTransit: true,
        IsSpecialRecall: true
      }, {
        RecordId: 3,
        IsPriority: false,
        IsInTransit: true,
        IsSpecialRecall: true
      }]);
      
      this.moveUp = function(data) {
        var idx = self.itemsToReceive.indexOf(data),
          tmp = self.itemsToReceive.splice(idx, 1);
    
        self.itemsToReceive.splice(idx - 1, 0, tmp[0]);
      };
      
      this.moveDown = function(data) {
        var idx = self.itemsToReceive.indexOf(data),
          tmp = self.itemsToReceive.splice(idx, 1);
    
        self.itemsToReceive.splice(idx + 1, 0, tmp[0]);
      };
      
      this.loadGridServerSide = function() {
        self.itemsToReceive([{
          RecordId: 1,
          IsPriority: true,
          IsInTransit: true,
          IsSpecialRecall: true
        }]);
      }
    }
    
    ko.applyBindings(new AppModel());
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    <button data-bind="click: loadGridServerSide" class="btn btn-primary">Server Side Invoke</button>
    <table class="table static-table table-bordered table-hover no-bottom-margin">
      <thead>
        <tr>
          <th>Item Number</th>
          <th>Priority?</th>
          <th>Transit?</th>
          <th>SpecialRecall?</th>
        </tr>
      </thead>
      <tbody data-bind="foreach: itemsToReceive">
        <tr>
          <td data-bind="text: RecordId"></td>
          <td>
            <input type="checkbox" data-bind="checked: IsPriority" />
          </td>
          <td>
            <input type="checkbox" data-bind="checked: IsInTransit" />
          </td>
          <td>
            <input type="checkbox" data-bind="checked: IsSpecialRecall" />
          </td>
          <td>
            <button data-bind="disable: $index() === 0, click: $parent.moveUp">Up</button>
            <button data-bind="disable: $index() === $parent.itemsToReceive().length - 1, click: $parent.moveDown">Down</button>
          </td>
        </tr>
      </tbody>
    </table>

    Using Drag and Drop would be somewhat more complicated, because the re-ordering happens in the UI and needs to be reflected into the data model. You would do it in a custom binding handler, and such a handler has been written. Here is an article about it.