Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
78
rated 0 times [  79] [ 1]  / answers: 1 / hits: 11377  / 11 Years ago, wed, january 29, 2014, 12:00:00

I am using some of the Knockout utility functions described brilliantly here: http://www.knockmeout.net/2011/04/utility-functions-in-knockoutjs.html



I want to do an arrayMap to select certain properties based on a condition, e.g.



return ko.utils.arrayMap(myObservableArray(), function (item) {
return item.Label;
});


Say for example this produces the following output:



[null, , SomeLabel, null, SomeOtherLabel]


I want to select the properties based on a condition, so I try:



return ko.utils.arrayMap(myObservableArray(), function (item) {
if (item.Label && item.Label !== ) {
return item.Label;
}
});


However then you end up with an array like:



[undefined, undefined, SomeLabel, undefined, SomeOtherLabel]


I've also tried this:



return ko.utils.arrayMap(myObservableArray(), function (item) {
return (item.Label && item.Label !== ) ? item.Label : false;
});


but you get:



[false, false, SomeLabel, false, SomeOtherLabel]


So I am then having to do:



var itemsWithLabels = ko.utils.arrayFilter(myObservableArray(), function (item) {
return (item.Label && item.Label !== );
});
return ko.utils.arrayMap(itemsWithLabels, function (item) {
return item.Label;
});


Which will give me:



[SomeLabel, SomeOtherLabel]


Is there a more efficient way of accomplishing this, in one shot, using ko.utils or similar?


More From » knockout.js

 Answers
3

As you noticed, with ko.utils.arrayMap it is expected your callback returns something. SO this is a 'dumb function' that always appends the return value of the callback to the array. Returning undefined, null or false does not omit the value from the resulting array.



arrayFilter allows for no way to modify the filtered item: the original item will be pushed to the result array.



So in short, this cannot be done more efficiently with the ko.utils.array* functions. You could combine them and make the code a bit more verbose, perhaps even put them in a computed:



var itemsWithLabels = ko.computed(function () {
return ko.utils.arrayMap(ko.utils.arrayFilter(myObservableArray(), function (item) {
return item.Label && item.Label.length;
}), function (filteredItem) {
return filteredItem.Label;
});
});


But this is the best you can do. I chose to first apply the filter, and afterwards do the mapping, because it seems to me the mapping would be more expensive than the filtering. But that's just a hunch.



Maybe a library such as Underscore provides methods to do this directly.



It's also fairly easy to write such a method yourself (and possible put it in ko.utils if you wish)



    ko.utils.arrayMapFilter = function (array, mapping) {
array = array || [];
var result = [], mapResult;
for (var i = 0, j = array.length; i < j; i++) {
mapResult = mapping(array[i]);
if (mapResult) {
result.push(mapResult);
}
}
return result;
},


your mapping callback can now return falsy values such as 0, , false, null or undefined, and they won't end up in the array.



If you want to permit a few of the above values anyway (such as 0 or ), then just change the line:



if (mapResult)


to something more strict, like:



if (mapResult !== undefined && mapResult !== null)

[#48248] Tuesday, January 28, 2014, 11 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
anabellejaynav

Total Points: 176
Total Questions: 105
Total Answers: 105

Location: Croatia
Member since Fri, Sep 11, 2020
4 Years ago
;