danfo danfo - 1 month ago 27
Javascript Question

Vue JS use array to filterBy another array?

Yep, it's me again. I'm trying to filter an array based on an array of strings. So while a single string filter is easy with Vue...

<div v-for="item in items | filterBy 'words' in 'property'">


...multiple search strings becomes more complex. There's been several questions about how to do this on StackOverflow already, but very few answers. Currently I'm trying to repurpose the custom filter found here for my needs, but it's not working.

My use case:
I have an array of groups (checkboxes) that the user can select to filter an array of people. Each person is assigned to one or more groups so if any one of their groups is selected by the user, that person should show up.

So my templates look like this:

<template v-for="group in ensemble_groups">
<input name="select_group[]" id="group_@{{ $index }}"
:value="group"
v-model="selected_groups"
type="checkbox">
<label for="group_@{{ $index }}">@{{ group }}</label>
</template>

<template v-for="person in cast | filterBy selectGroups">
<div>@{{ person.actor_name }}</div>
</template>


You see my custom filter
selectGroups
there? Here's my Vue arrays:

selected_groups: [],
ensemble_groups: ["Leads","Understudies","Children","Ensemble"],

cast: [
{
actor_name: "Dave",
groups: ["Leads"],
},
{
actor_name: "Jill",
groups: ["Leads"],
},
{
actor_name: "Sam",
groups: ["Children","Ensemble"],
},
{
actor_name: "Austin",
groups: ["Understudies","Ensemble"],
},
],


And finally here's the custom filter. I can't tell if it's even being triggered or not, because when I click on a group checkbox, nothing happens.

filters: {
selectGroups: function() {
if (!selected_groups || selected_groups.length === 0) {
return cast;
}
return this.recursiveFilter(cast, selected_groups, 0);
}
},
methods: {
recursiveFilter: function(cast, selected_groups, currentPosition) {
if (currentPosition+1 > selected_groups.length)
return cast;
var new_cast;
new_cast = cast.filter(function(person) {
for (group of person.groups) {
if (group.value == selected_groups[currentPosition])
return true;
}
});
return this.recursiveFilter(new_cast, selected_groups, currentPosition+1);
}
}


So if the user selects
Leads
only Dave and Jill should appear. If the user then checks
Children
, Dave, Jill, and Sam should appear. I'm so close!

Answer

I would use a computed property instead of a filter and a method.

I'd go through each cast member and if any of their groups is in selected_groups I'd allow it through the filter. I'd so this using Array.some.

results: function() {
  var self = this
  return self.cast.filter(function(person) {
    return person.groups.some(function(group) {
      return self.selected_groups.indexOf(group) !== 1
    })
  })
},

Here's a quick demo I set up, might be useful: http://jsfiddle.net/crswll/df4Lnuw6/8/

Comments