Kevin
Kevin

Reputation: 241

Knockout HTML Table Group by Parent

I have a HTML table which is created dynamically by KnockoutJS...

I want the output of the table to be grouped by Parent as shown here...

enter image description here

How do I do this?

<table class="table table-hover">
  <thead>
    <tr>
      <th>Task ID</th>
      <th>Task name</th>
      <th>Parent</th>
    </tr>
  </thead>
  <tbody data-bind="foreach: tasks">
    <tr>
      <td data-bind="text: TaskID"></td>
      <td data-bind="text: TaskName"></td>
      <td data-bind="text: Parent"></td>
    </tr>
  </tbody>
</table>

_

var viewModel = function(data) {
    var self = this;

    // variables
    self.currentTask = ko.observable();

    self.tasks = ko.observableArray([
    {TaskID: 1, TaskName: "ManualItems", Parent: 3},
    {TaskID: 2, TaskName: "Trades", Parent: null},
    {TaskID: 3, TaskName: "Positions", Parent: null},
    {TaskID: 4, TaskName: "Rec", Parent: 3},
    {TaskID: 5, TaskName: "Cash", Parent: null},
    {TaskID: 6, TaskName: "ReportA", Parent: 5},
    {TaskID: 7, TaskName: "FileIn", Parent: 2},
    {TaskID: 8, TaskName: "ReportB", Parent: 5}
    ]); 

};

ko.applyBindings(new viewModel());

http://jsfiddle.net/qa0gbf9q/

Upvotes: 1

Views: 1131

Answers (2)

Bryan Dellinger
Bryan Dellinger

Reputation: 5294

Here is another solution this time leaving your original observable array alone and using the filter functionality to create a parent child behavior. run snippet below.

var viewModel = function(data) {
  var self = this;

  self.tasks = ko.observableArray([{
    TaskID: 1,
    TaskName: "ManualItems",
    Parent: 3
  }, {
    TaskID: 2,
    TaskName: "Trades",
    Parent: null
  }, {
    TaskID: 3,
    TaskName: "Positions",
    Parent: null
  }, {
    TaskID: 4,
    TaskName: "Rec",
    Parent: 3
  }, {
    TaskID: 5,
    TaskName: "Cash",
    Parent: null
  }, {
    TaskID: 6,
    TaskName: "ReportA",
    Parent: 5
  }, {
    TaskID: 7,
    TaskName: "FileIn",
    Parent: 2
  }, {
    TaskID: 8,
    TaskName: "ReportB",
    Parent: 5
  }]);

  self.getChildren = function(row) {
    return ko.utils.arrayFilter(this.tasks(), function(item) {
      return item.Parent === row.TaskID
    });
  }



  self.filteredtasks = ko.computed(function() {
    return ko.utils.arrayFilter(this.tasks(), function(item) {
      return !item.Parent;
    });
  }, this);


};

ko.applyBindings(new viewModel());
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<table class="table table-hover">
  <thead>
    <tr>
      <th>Parent</th>
      <th>Parent Name</th>
      <th>Task Id</th>
      <th>Task Name</th>
    </tr>
  </thead>
  <tbody>
    <!-- ko foreach: filteredtasks -->
    <tr>
      <td data-bind="text: TaskID"></td>
      <td data-bind="text: TaskName"></td>
      <td></td>
      <td></td>
    </tr>
    <!-- ko foreach: $root.getChildren($data) -->
    <tr>
      <td></td>
      <td></td>
      <td data-bind="text: TaskID"></td>
      <td data-bind="text: TaskName"></td>
    </tr>
    <!-- /ko -->
    <!-- /ko -->

  </tbody>
</table>

Upvotes: 1

Bryan Dellinger
Bryan Dellinger

Reputation: 5294

are you allowed to change the structure of your observable array around a bit? if so run the snippet below. If not as mentioned above the pure computed are the way to go. have a look at this link http://www.knockmeout.net/2011/04/utility-functions-in-knockoutjs.html. it has all the functions you need. probaly flatten array and get unique values for your parents. then use the filter for the children. if you are still having difficulty let us know and I can try to work one up using those utilities.

function task(name, id, data) {
  var self = this;
  this.name = ko.observable(name);
  this.id = ko.observable(id);
  this.children = ko.observableArray(data);
}

var viewModel = function(data) {
  var self = this;

  // variables
  self.currentTask = ko.observable();
  self.tasks = ko.observableArray([
    new task('Trades', 2, [{
      Id: 7,
      Name: 'FileIn'
    }]),
    new task('Positions', 3, [{
      Id: 1,
      Name: 'ManualItems'
    }, {
      Id: 4,
      Name: 'Rec'
    }]),
    new task('Cash', 5, [{
      Id: 6,
      Name: 'ReportA'
    }, {
      Id: 8,
      Name: 'ReportB'
    }])
  ]);

  /*self.tasks = ko.observableArray([
   	{TaskID: 1, TaskName: "ManualItems", Parent: 3},
    {TaskID: 2, TaskName: "Trades", Parent: null},
    {TaskID: 3, TaskName: "Positions", Parent: null},
    {TaskID: 4, TaskName: "Rec", Parent: 3},
    {TaskID: 5, TaskName: "Cash", Parent: null},
    {TaskID: 6, TaskName: "ReportA", Parent: 5},
    {TaskID: 7, TaskName: "FileIn", Parent: 2},
    {TaskID: 8, TaskName: "ReportB", Parent: 5}
    ]); */

};

ko.applyBindings(new viewModel());
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>


<table class="table table-hover">
  <thead>
    <tr>
      <th>Parent</th>
      <th>Parent Name</th>
      <th>Task Id</th>
      <th>Task Name</th>
    </tr>
  </thead>
  <tbody data-bind="foreach: tasks">
    <tr>
      <td data-bind="text: id"></td>
      <td data-bind="text: name"></td>
      <td></td>
      <td></td>
    </tr>
    <!-- ko foreach: children -->
    <tr>
      <td></td>
      <td></td>
      <td data-bind="text: Id"></td>
      <td data-bind="text: Name"></td>
    </tr>
    <!-- /ko -->
  </tbody>
</table>

Upvotes: 0

Related Questions