AngularJS filter based on array of strings?
I'm having a hard time wrapping my head around how to go about doing an Angular filter to solve a problem that I'm running into.
Here's a basic example of my data structure, an array of tasks:
var tasks = [
{ Title: "This is a task title",
Tags: ["Test","Tag","One","Two","Three"] },
{ Title: "Another test tag title",
Tags: ["Some", "More", "Tags"] },
{ Title: "One more, why not",
Tags: ["I","Like","Dirt"] },
{ Title: "Last one!",
Tags: ["You","Like","Dirt"] }
];
So each object has an array of tags. For the sake of example let's say I am outputting each of those objects as a row in a table.
Once the pages ng-controller is initialized, I'm grabbing all of the tags from all of the tasks (without duplicates) and assembling them into a tags
array.
Then, I'm outputting those tags as toggle-able buttons on the page. All the buttons are blue by default, meaning "active" (in other words: show tasks with this tag contained therein). I need to be able to click on one of those buttons to "toggle off" that tag -- which will filter out any tasks rows in the table wherein the task has that tag.
Like so for visual reference -- grey = "hide tasks whose tags contains this tag", blue = "show tasks whose tags contain this tag":
.
Clicking on a button turns it grey, filtering out any tasks in the table that have that tag. I can then click the buttons again to toggle that tag back on, re-showing all tasks with that tag.
Am I explaining this clearly enough? It's a confusing system.
Anyway, I've tried the following:
ng-filter="task in filteredWithTags = (tasks | filter: { tags: arrayOfTags }"
to no avail.
Someone mind pointing me in the right direction? :)
PS: I had this working earlier this week by calling a filterByTag(tag)
function in my controller. This would loop through every task in the array of tasks and if it had the tag that matched, it would hide that task. Similarly re-activating a tag would do the same thing, loop through everyone and work the magic... but I'm told that my method was slow + overkill, because "angular filters can handle all of that for you, and it will be more best-practicy". Hence, why I'm here, trying to figure out how to let Angular do the work for me :)
Any help is appreciated!
Solution 1:
You could write a custom filter. The filter would be given the list of active tags, tags
, and the array of tasks to be filtered, tasks
, and would output an array of filtered tags. It will be much the same as what you've already done, but with no extra function on the scope.
angular.module('myApp').filter('selectedTags', function() {
return function(tasks, tags) {
return tasks.filter(function(task) {
for (var i in task.Tags) {
if (tags.indexOf(task.Tags[i]) != -1) {
return true;
}
}
return false;
});
};
});
Then you can use it like
<ul>
<li ng-repeat="task in tasks | selectedTags:tags"></li>
</ul>
Check out this fiddle.