Reputation: 241
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...
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());
Upvotes: 1
Views: 1131
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
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