Corcor
Corcor

Reputation: 91

v-show if nested array items match filtered array

I have to write a Vue webapp that will take multiple filters, push them to an array and on a click method, check the filters arrays values and if any of the values match any of the nested values inside the tiles nested array, show the tiles where there is a match. So, my filter array could have:

filters: ['cookies', 'jogging']

And my nested tiles array will have:

tiles: [
 {
  "name": "Greg",
  "food": ["cookies", "chips", "burgers"],
  "activities": ["drawing", "watching movies"]
  "favourite places": ["the parks", "movie theatre"]
 },{
  "name": "Robyn",
  "food": ["cookies", "hotdogs", "fish"],
  "activities": ["reading", "jogging"]
  "favourite places": ["beach", "theme parks"]
 },{
  "name": "John",
  "food": ["sushi", "candy", "fruit"],
  "activities": ["writing", "planning"]
  "favourite places": ["the moon", "venus"]
 }
]

In the above example, the tiles that would show would be Robyn, since she likes cookies and jogging.

So far my thinking is writing out a for loop that checks the the values inside the nested array, which I got from this solution:

https://stackoverflow.com/a/25926600/1159683

However i'm failing to make the connection for just showing the item inside a v-for/v-show. I've got the method down for pushing all the filters to the filter array, but when it comes to matching it with the nested array and showing them based on the match, i'm at a loss. Preferably i'd like to write this out in vanilla js (es5).

Any help is appreciated.

Thank you!

Upvotes: 0

Views: 297

Answers (1)

shanemgrey
shanemgrey

Reputation: 2378

computed: {
  fullyMatchedTiles () {
    // Matches must contain all terms from filter array

    return this.tiles.filter(obj=> {

      // Filter the filters to get matched count
      let matchedFilters = this.filters.filter(filterItem=> {

        // Check each property by looping keys
        for (key in obj) {

          // Only evaluate if property is an array
          if (Array.isArray(obj[key])) {

            // Return true if filterItem found in obj
            if (obj[key].some(r=> filterItem.indexOf(r) >= 0)) {
              return true
            }
          }
        }
      })
      return this.filters.length === matchedFilters.length
    }) 
  },

  partiallyMatchedTiles () {
    // Matches must contain at least one term from filter array
    // Check each object in the array
    return this.tiles.filter(obj=> {

      // Check each property by looping keys
      for (key in obj) {

        // Only evaluate if property is an array
        if (Array.isArray(obj[key])) {

          // Return true to the filter function if matched, otherwise keep looping
          if (obj[key].some(r=> this.filters.indexOf(r) >= 0)) {
            return true
          }
        }
      }
    })
  },
},

Sorry it's not es5. I love the new features too much to take the time to go back 5 years.

For a full example showing the filtered object returned in vue, check this codepen https://codepen.io/shanemgrey/pen/jOErWbe

I think you were describing doing the filtering in the v-for. It seems like too complex of logic to try to accomplish it with the filtering available in v-for.

I would instead do as shown by breaking down the array in a new computed property and then using the resulting filtered array however you like in the template.

Upvotes: 2

Related Questions