Reputation: 1197
I've been battling with what seems like it should be a really simple Knockout.js task for a number of hours, and after reading multiple websites and questions on SO, I'm still stumped!
Here is the fiddle: http://jsfiddle.net/PL8UW/
Essentially I have a table with a "status" column that is bound to a knockout viewmodel.
I also have an observable object that should allow you to filter on various statuses
If i bind the table directly to the data object everything shows, but if I bind to the computed, then nothing shows.
HTML:
<form>
<input id="foo" type="checkbox" checked /> Foo
<input id="bar" type="checkbox" checked /> Bar
</form>
<div id="tableDiv">
<table>
<thead>
<tr>
<th>Id</th>
<th>Status</th>
</tr>
</thead>
<tbody data-bind="foreach: filteredData">
<tr>
<td><span data-bind="html: id"></span></td>
<td><span data-bind="html: status"></span></td>
</tr>
</tbody>
</table>
</div>
javascript: var data = [ {"id": 1, "status": "foo"}, {"id": 2, "status": "bar"}, {"id": 3, "status": "foo"}, {"id": 4, "status": "foo"}, {"id": 5, "status": "bar"}];
var viewModel = {
tableData: ko.observableArray(data),
filter: ko.observable({'foo': ko.observable(true), 'bar': ko.observable(true)}),
filteredData: ko.computed(function() {
return ko.utils.arrayFilter(viewModel.tableData, function(item) {
return viewModel.filter[item.Status];
});
})
};
ko.applyBindings(viewModel, document.getElementById('tableDiv'));
$('input[type=checkbox]').click(function () {
viewModel.filter[this.id] = this.checked;
});
Upvotes: 0
Views: 369
Reputation: 139778
You have numerous smaller, bigger errors in your fiddle which are coming from two fundamental problem (beside the fact that your design your storing the filter and little bit complicated and you are mixing the jQuery event handlers with Kncokout viewmodels):
ko.observable
is returning a function so to get its value you need to write someObservable()
and to set its value you need to write someObservable(newValue)
(documentation)
you need to use the deferEvaluation: true
option if you are using ko.computed
declared on object literals in order to access the object itself inside the computed. (see also: Difference between knockout View Models declared as object literals vs functions)
So here is a fixed version of your code with comments:
var viewModel = {
tableData: ko.observableArray(data),
filter: ko.observable({'foo': ko.observable(true), 'bar': ko.observable(true)}),
filteredData: ko.computed(function() {
// missing () after viewModel.tableData
return ko.utils.arrayFilter(viewModel.tableData(), function(item) {
//missing () after filter and at the end
//typo: Satus should be status
return viewModel.filter()[item.status]();
});
//deferEvaluation was needed to refernce viewModel inside the computed
}, null, {deferEvaluation: true})
};
ko.applyBindings(viewModel, document.getElementById('tableDiv'));
$('input[type=checkbox]').click(function () {
//missing () after filter missing () to set the observable value
viewModel.filter()[this.id](this.checked);
});
Demo JSFiddle.
Here is a different solution using the checked
binding for handling the filter:
Demo JSFiddle.
Upvotes: 1