Vue: [feature request] local variables in v-for

Created on 27 Mar 2016  ·  11Comments  ·  Source: vuejs/vue

Here is a nested v-for case

<div v-for="x in xs">
      <div v-if="calcYs(x).length>0">
            <div v-for="y in calcYs(x)"> {{y}} </div>
      </div>
      <div v-else>fallback content</div>
</su-tab>

where calcYs is a method. As you can see, for every x, calcYs(x) will be called twice (if not empty) which is not necessary. It would be more efficient if we can bind the result of calcYs(x) to some local variables inside v-for.

Most helpful comment

Could this be accomplished with a custom directive? eg,

<div v-for="x in xs">
    <div v-with="ys = calcYs(x)" v-if="ys.length>0">
        <div v-for="y in ys"> {{y}} </div>
    </div>
    <div v-else>fallback content</div>
</div>

All 11 comments

This complicates the template quite a bit with very little benefits. I don't think it's worth it.

Could this be accomplished with a custom directive? eg,

<div v-for="x in xs">
    <div v-with="ys = calcYs(x)" v-if="ys.length>0">
        <div v-for="y in ys"> {{y}} </div>
    </div>
    <div v-else>fallback content</div>
</div>

I have a similar problem. I would like to do something like this v-for="project.relations().tasks()".

What would the recommended approach be? A new component just to list task names seems like overkill.

Please disregard my previous post. It was working all along.

Code below generates "active table". It would be nice to have a local v-for variable for current index: (r-1)10 + (c-1). Something like: v-var="currIdx = (r-1)10 + (c-1)"

<p v-for="r in 5" style="margin: 1px">
    <span v-for="c in 10"
        class="bordered"
        style="margin: 1px; width: 30px; height: 30px; display: inline-block;"
        @mouseover="hoverIndex = (r-1)*10 + (c-1)"
        @mouseleave="hoverIndex = -1"
        @click="selectIndex = (r-1)*10 + (c-1)"
        :class="{hovered: hoverIndex == (r-1)*10 + (c-1) && showHover,
                 selected: selectIndex == (r-1)*10 + (c-1)}"> 
    {{ (r-1)*10 + c }} </span>
</p> 

I too think that having a v-with or v-var directive would help greatly with performance.
For instance, I have a template where an array is parsed with .find() every time I need to display a property from that object.

<div v-if="subtotalRows.includes(payment.term)">
    <div>{{ findSubtotal(payment.term).shortDescription }}</div>
    <div>{{ anFloat(findSubtotal(payment.term).int) }}</div>
    <div>{{ anFloat(findSubtotal(payment.term).cap) }}</div>
    <div>{{ anFloat(findSubtotal(payment.term).ins) }}</div>
    <div>{{ an(findSubtotal(payment.term).fee) }}</div>
    <div>{{ anFloat(findSubtotal(payment.term).ter) }}</div>
</div>

and the method:

findSubtotal(termIndex) {
    return this.subtotals.find(st => st.tpTerms === termIndex);
},

Is there a workaround I'm missing here to improve performance?
If not, I think reopening this issue could solve that problem, thanks!

@AlexandreBonneau
As a quick hack you can try this way:

<div v-if="subtotalRows.includes(payment.term)">
    <template v-for="scope in [{ subtotal: findSubtotal(payment.term) }]">
        <div>{{ scope.subtotal.shortDescription }}</div>
        <div>{{ anFloat(scope.subtotal.int) }}</div>
        <div>{{ anFloat(scope.subtotal.cap) }}</div>
        <div>{{ anFloat(scope.subtotal.ins) }}</div>
        <div>{{ an(scope.subtotal.fee) }}</div>
        <div>{{ anFloat(scope.subtotal.ter) }}</div>
    </template>
</div>

this issue is one year old 😅
You can give https://github.com/posva/vue-local-scope a try too

Sometimes it turns out to be more convenient to move repeating code out to a separate component.

Sometimes it turns out to be more convenient to move repeating code out to a separate component.

It can't cover all use cases, but it was a nice and working advice for me. A small and easy-to-maintain subcomponent.

Was this page helpful?
0 / 5 - 0 ratings