Reputation: 73
I am new to Knockout. I'm successfully pulling data, but trying to filter it based on whether the record is active or not active. When I do this, it's sending the right values through, but my observable array is empty.
I'm filling it with ajax. My understanding is that I fill the observable array, and do not need to do any other hits to the server unless I want to write to the database or get new data. So once that observable array has data, I should be able to filter it without hitting the database again. This doesn't seem to work for me. I think I'm doing something wrong. Thoughts?
Here is the code:
var sgsoip = window.sgsoip || {};
sgsoip.FunctionalAreaViewModel = function (ko, db) {
//'use strict';
var self = this;
self.functionalAreas = ko.observableArray([])
self.headers = [
{ title: '', sortPropertyName: '', asc: true },
{ title: 'Functional Area Name', sortPropertyName: 'FunctionalAreaName', asc: true },
{ title: 'Active', sortPropertyName: 'FunctionalAreaActive', asc: true }
];
self.filters = [
{ title: "Show All", filter: null },
{ title: "Active", filter: function (item) { return item.FunctionalAreaActive == 'true'; } },
{ title: "Inactive", filter: function (item) { return item.FunctionalAreaActive == 'false'; } }
];
self.activeFilter = ko.observable(self.filters[0].filter);
self.setActiveFilter = function (model, event) {
self.activeFilter(model.filter);
}
self.filteredItems = ko.computed(function () {
if (self.activeFilter()) {
return ko.utils.arrayFilter(self.functionalAreas, self.activeFilter()); //When hitting filter self.functionalAreas is empty
} else {
return self.functionalAreas(); //this works as expected
}
});
self.activeSort = self.headers[1];
function _init() {
db.getFunctionalAreas(function (data) {
//var a = [];
ko.utils.arrayForEach(data || [], function (item) {
self.functionalAreas.push(new sgsoip.FunctionalArea(item.FunctionalAreaID, item.FunctionalAreaName, item.FunctionalAreaActive));
});
//self.functionalAreas(a);
});
}
_init();
return {
functionalAreas: functionalAreas,
sortedFunctionalAreas: sortedFunctionalAreas,
removeFunctionalArea: removeFunctionalArea
};
}(ko, sgsoip.DataContext);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<div class="btn-group" data-bind="foreach: filters">
<button class="btn btn-small" data-bind="click: setActiveFilter, text: title"></button>
</div>
<table class="table" id="gridoutput">
<thead>
<tr data-bind="foreach: headers">
<th><a href="#" data-bind="click: filteredItems, text: title"></a></th>
</tr>
</thead>
<tbody data-bind="foreach: filteredItems">
<tr>
<td><a href="javascript:void(0);" data-bind="click: removeFunctionalArea" title="Delete"><i class="icon icon-trash"></i></a></td>
<td data-bind="text: FunctionalAreaName"></td>
<td data-bind="text: FunctionalAreaActive"></td>
</tr>
</tbody>
</table>
Edit - Added some missing stuff for those that asked.
var sgsoip = window.sgsoip || {};
sgsoip.DataContext = (function ($) {
'use strict';
var me = {
getFunctionalAreas: getFunctionalAreas,
removeFunctionalArea: removeFunctionalArea,
saveFunctionalArea: saveFunctionalArea
};
function getFunctionalAreas(callback) {
var functionalareas = null;
if ($.isFunction(callback)) {
//functionalareas = localStorage["functionalareas"];
//alert('test');
//if (functionalareas != "undefined") {
// callback(functionalareas);
//} else {
$.getJSON('/FunctionalAreas/GetJsonData', function (data) {
//localStorage["functionalareas"] = JSON.stringify(data.FunctionalAreas);
callback(data);
});
//}
}
}
function removeFunctionalArea(functionalArea) {
}
function saveFunctionalArea(functionalArea) {
}
return me;
})(jQuery);
var sgsoip = window.sgsoip || {};
sgsoip.FunctionalArea = function (FunctionalAreaID, FunctionalAreaName, FunctionalAreaActive) {
'use strict';
this.FunctionalAreaID = ko.observable(FunctionalAreaID);
this.FunctionalAreaName = ko.observable(FunctionalAreaName).extend({ required: "Functional Area Name is required" });
this.FunctionalAreaActive = ko.observable(FunctionalAreaActive).extend({ required: "Active is required" });
this.HasError = ko.pureComputed(function () {
return this.FunctionalAreaActive.hasError() || this.FunctionalAreaName.hasError();
}, this);
};
EDIT Looks like I can add more clarification. It is not losing data. I stepped all the way through the Knockout code. And it does cycle through the observable to compare.
I get to the following piece of code:
arrayFilter: function (array, predicate) {
array = array || [];
var result = [];
for (var i = 0, j = array.length; i < j; i++)
if (predicate(array[i], i))
result.push(array[i]);
return result;
},
And it never executes the result.push(array[i]) line.
Upvotes: 0
Views: 773
Reputation: 3835
When iterating or in any other way working with your observable array, you need to remember to add the parenthesis at the end, like so:
return ko.utils.arrayFilter(self.functionalAreas(), self.activeFilter());
It's only when using methods that are actually implemented on the observableArray (like push, remove etc), that you can leave out the parenthesis.
Upvotes: 1