Uriah Gray
Uriah Gray

Reputation: 15

data from child array in v-if

I am trying to access the data from a child array and use that in my v-if

Here is my data and my code. Any help would be great, even just links to the correct documentation.

<div  class='post' v-for="message in messages"  v-if='["Food","Featured"].includes(tag) || tag === ""'>
            
            <h2>{{message.text}}</h2>

            <div v-for="category in message.categories">
              {{category.name}}
            </div> 

</div>

instead of

v-if='["Food","Featured"] I have been trying v-if='[category in message.categories]

Obviously that is not correct, but how do you correctly send data from a nested array UP to the v-if statement?

data is here:

[
   {
      "text":"Featured food content",
      "categories":[
         {
            "name":"Featured",
            "ID": "189"
         },
         {
            "name":"Food",
            "ID": "190"
         }
      ]
   },
   {
      "text":"Featured content",
      "categories":[
         {
            "name":"Featured",
            "ID": "189"
         }
      ]
   }
]

Thank you for all the help. This my solution until I can learn how to use computed properties correctly.

      <template v-for="message in messages">
        <div class='post' v-if='message.categories.map(c => c.name).includes(tag) || tag === ""'>
            
            <h2>{{message.text}}</h2>

            <div v-for="category in message.categories">
              {{category.name}}
            </div> 

        </div>
      </template>

Upvotes: 0

Views: 951

Answers (3)

Billy Brown
Billy Brown

Reputation: 2342

(This answer disregards the issue with using both v-for and v-if at the same time, which is discussed quite well here: https://stackoverflow.com/a/54531252/1406083)

If you want to check the category names, you can use .map(...) on your array, which will return a new array that you can then call .includes(tag) on. Put this in your v-if:

tag === "" || message.categories.map(c => c.name).includes(tag)

Upvotes: 0

Dylan Landry
Dylan Landry

Reputation: 1290

Here's something that might do what you want, let me know. I couldn't tell exactly what your problem was from your code.

<div id="app">
  <div
    v-for="message in messages"
    v-if="messageHasCategory(message, currentCategory)"
  >
    {{message.text}}
  </div>
</div>

const app = new Vue({
  el: "#app",
  data: {
    currentCategory: 'Food',
    messages: [{
      text: 'Food message',
      categories: [{
        name: "Food"
      }]
    }, {
      text: 'Featured message',
      categories: [{
        name: "Featured"
      }]
    }]
  },
  methods: {
    messageHasCategory(message, categoryName) {
      return message.categories.find(c => {
        return c.name == categoryName;
      })
    }
  }
})

Or you can combine the v-for and v-if into a single computed property like @zerbene suggests.

<div id="app">
  <div v-for="message in currentCategoryMessages">
    {{message.text}}
  </div>
</div>

const app = new Vue({
  el: "#app",
  data: {
    currentCategory: 'Food',
    messages: [{
      text: 'Food message',
      categories: [{
        name: "Food"
      }]
    }, {
      text: 'Featured message',
      categories: [{
        name: "Featured"
      }]
    }]
  },
  computed: {
    currentCategoryMessages() {
      return this.messages.filter(m => {
        return m.categories.map(c => c.name).includes(this.currentCategory);
      })
    }
  },
})

Codepen: https://codepen.io/dyllandry-the-styleful/pen/vYKEjeb

Upvotes: 1

zerbene
zerbene

Reputation: 1492

Warning: v-for and v-if not working together in Vue.js. For the v-if, you need to transform it as COMPUTED properties like

this.data is your nested data that you have declared. In filter() you write your test.

computed: {
  testedValues: function () {
    return this.data.filter(i => i.categories !== '')
  }
}

and after you write what you want

<div v-for="item in testedValues">{{item}}</div>

Upvotes: 2

Related Questions