I have the array of named items each of them contains other array of named items (some kind of tree). I need implementation of filtering by name in both arrays.
So I check name each item of the first array:
I have implemented it in the next way:
ko.utils.stringStartsWith = function (string, startsWith) {
if (startsWith.length > string.length)
return false;
return string.substring(0, startsWith.length) === startsWith;
};
$(function () {
var vm = {
search: ko.observable(''),
items: ko.observableArray([])
};
//jsonData - my data
$.each(jsonData, function (i, jItem) {
var item = {
name: jItem.Name,
search: ko.observable(''),
subItems: ko.observableArray([])
};
$.each(jItem.Items, function (j, jsubItem) {
var subItem = {
name: jsubItem.Name,
};
item.subItems.push(subItem);
});
item.filteredSubItems = ko.computed(function () {
var self = this;
return ko.utils.arrayFilter(this.subItems(), function (fsubItem) {
if (self.search().length == 0
|| ko.utils.stringStartsWith(fsubItem.name.toLowerCase(), self.search().toLowerCase())) {
return true;
}
return false;
});
}, item);
vm.items.push(item);
});
vm.filteredItems = ko.computed(function () {
var self = this;
return ko.utils.arrayFilter(this.items(), function (fitem) {
if (self.search().length == 0
|| ko.utils.stringStartsWith(fitem.name.toLowerCase(), self.search().toLowerCase())) {
fitem.search('');
return true;
}
fitem.search(self.search());
if (fitem.filteredSubItems().length != 0)
return true;
return false;
});
}, vm);
ko.applyBindings(vm);
});
So it works well but calculating of filteredItems
looks like ugly workaround for me. Moreover, I care about performance of my solution.
Does anybody know more glade solution for this?
I asked this question half of a year ago and I forgot to say that I found answer on this question. Nice and simple solution is Knockout Mapping.