The $scope.categories array is being populated from a multi-select element in AngularJS.
$scope.categories = ["Adventure", "Strategy"]
I need to compare this array against the categories array in the items array below:
$scope.items = [
{
title: "Star Wars",
categories: ["Adventure"]
}, {
title: "Star Search",
categories: ["Adventure", "Strategy"]
}, {
title: "Star Trek",
categories: ["Adventure", "Family"]
}, {
title: "Star Wars",
categories: ["Family", "Strategy"]
}];
Both values in $scope.categories need to match the same values in $scope.items.categories, for the object to be pushed to an output array.
With the resulting $scope.filtered array being (items1):
{
title: "Star Search",
categories: ["Adventure", "Strategy"]
}
I have the logic until the loop needs to reiterate... but how?
Then I am comparing the $scope.categories value against the value of $scope.item.categories
for (var i = 0; i < categories.length; i++) {
for (var j = 0; j < items.length; j++) {
for (var k = 0; k < items[j].categories.length; k++) {
if(categories[i] == items[j].categories[k]) {
console.log("The value of " + categories[i] + ", matches " + items[j].categories[k]);
} else {
console.log("The value of " + categories[i] + ", is not a match");
}
}
}
}
Here is a JSbin example
It's much simpler really:
var filtered = items.filter(function(i) {
return categories.every(function(c) {
return i.categories.indexOf(c) >= 0
})
})
Array.prototype.filter
iterates an array and calls a callback function for each item. Each item that the callback function returns true for is included in the result array.
Array.prototype.every
iterates an array and calls a callback function for each item, returning true if the callback for ALL items returned true, and false otherwise.
In this use case, we're filtering the items array, and the filter callback returns true when all of the categories "pass" the every
callback condition, which is that the item categories contain the current (c
) category.
(Here's the fixed JSBin)
Here's a bit simpler solution. It assumes that ordering and capitalization are precise. Interestingly, filter + join solution outperforms the filter + every method. If top-level categories (i.e., var categories = ["Adventure", "Strategy"]
) is assumed to be a subset, then join()
function can be combined with indexOf
. The solution would still be simpler and performance is still slightly better.
See performance test here: http://jsfiddle.net/t3g3k7tL/.
var categories = ["Adventure", "Strategy"];
var items = [
{
title: "Star Wars",
categories: ["Adventure"]
}, {
title: "Star Search",
categories: ["Adventure", "Strategy"]
}, {
title: "Star Trek",
categories: ["Adventure", "Family"]
}, {
title: "Star Wars",
categories: ["Family", "Strategy"]
}
];
var filtered = items.filter(function(element) {
return element.categories.join("") === categories.join("");
});
If, top level categories is a subset and not exact match, then the following solution will work:
var filtered = items.filter(function(element) {
return element.categories.join("").indexOf(categories.join("")) !== -1;
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With