Reputation: 1992
I am using v-for
to create multiple <p>
elements. The v-for
is wrapped with the Vue <transition>
component because I want each <p>
to animate in if the v-if
condition is satisfied. Here is that code below:
<transition name="fade">
<p
v-for="(quote, idx) in game.quotes" <-- game.quotes comes from VUEX
:key="`game-quote-${idx}`"
class="quote-box__current_quote"
v-if="game.currentQuoteIdx === idx"
>"{{ quote.content }}"</p>
</transition>
However, I am getting ESLINT errors due to the vue/no-use-v-if-with-v-for
rule.
After researching that rule I was pointed to the following Vue style guide: https://v2.vuejs.org/v2/style-guide/#Avoid-v-if-with-v-for-essential. The guide recommends to avoid using v-for
and v-if
on the same element. I would like to animate each element in / out using the <transition>
wrapper component (only one <p>
tag should be visible at one time). Is there a more ideal way to achieve what I am doing without using v-if
and v-for
on the same element?
Additional Issue: I am getting the following error in reference to game.quotes
in v-for="(quote, idx) in game.quotes"
:
The 'undefined' variable inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if'.
game.quotes
is coming from Vuex and the array does not need to be filtered. Why is ESLINT recommending that I create a computed property and return a filtered array?
FILE ON GITHUB - Line 10
Upvotes: 3
Views: 888
Reputation: 3972
Create a computed property and return a filtered array. It's because your code is like filtering an array because of v-if attached inline with your v-for. In short, your just filtering the item you want to display in your loop. Why not using computed properties? It is safe and easy to handle.
Upvotes: 1
Reputation: 1078
The official documentation states that all conditional rendering within loops should be done through computed
functions. Do your conditional sifting in the computed (coming from a getter if you're using Vuex) and then put that in the template.
Official style guide for this: https://v2.vuejs.org/v2/style-guide/#Avoid-v-if-with-v-for-essential
Upvotes: 1
Reputation: 49208
Take this example, which is very similar to yours: Don't show the li
's that are not necessary. Combining v-for
and v-if
works perfectly fine, if not best practice. However, there is an easier way.
<h2>Items:</h2>
<ol id="list">
<li v-for="item in items" v-if="visible.includes(item)" :id="'item-'+item">
{{ item }}
</li>
</ol>
https://jsfiddle.net/oLjuy5bv/1/
What we can do instead, as the two other answers state, is created a computed method and calculate the list for the v-for
and remove the v-if
.
<h2>Items:</h2>
<ol id="list">
<li v-for="item in visible_items" :id="'item-'+item">
{{ item }}
</li>
</ol>
computed: {
visible_items () {
return this.items.filter(item => this.visible.includes(item))
}
},
https://jsfiddle.net/17Ln5mw8/
What I think you're after then is something like this, which uses a method due to the idx
and possibly game
context (I don't know the logic specifically):
<transition name="fade">
<p
v-for="(quote, idx) in gameQuotesByIdx(idx)"
:key="`game-quote-${idx}`"
class="quote-box__current_quote"
>"{{ quote.content }}"</p>
</transition>
methods: {
gameQuotesByIdx(idx) {
return ...
}
},
Where I think you might have an issue is reactivity, meaning the component might not respond to changes in array state (which computed resolves above for me). To get to that then, you might want to consider that a refactor.
Upvotes: 0