DatsunBing
DatsunBing

Reputation: 9076

Vue: How to conditionally render tr in tbody

I have a table body with multiple rows, such as this:

<table>
<tbody>
<tr>...</tr>
<tr>...</tr>
</tbody>
</table>

I want to conditionally combine v-if an v-for, to conditionally render one or more additional rows. The Vue manual says to wrap the v-for in a v-if, such as follows:

<div v-if="team.positions != null">
    <my-row v-for="position in team.positions"
                :position="position"
                :key="position.id">
    </my-row>
</div>

The problem is that I can't put a div in a tbody, or any other element for that matter. What's the solution?

Upvotes: 5

Views: 10012

Answers (3)

acdcjunior
acdcjunior

Reputation: 135832

In those situations where no element would fit, you can use <template>, like:

<template v-if="team.positions != null">
    <my-row v-for="position in team.positions"
                :position="position"
                :key="position.id">
    </my-row>
</template>

Demo:

new Vue({
  el: '#app',
  data: {
    showTwoRows: true
  }
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
  <table>
    <tr>
      <td>A</td><td>B</td>
    </tr>
    <template v-if="showTwoRows">
      <tr>
        <td>1</td><td>2</td>
      </tr>
      <tr>
        <td>3</td><td>4</td>
      </tr>
    </template>
    <tr>
      <td>C</td><td>D</td>
    </tr>
  </table>
  <button @click="showTwoRows = !showTwoRows">Toggle two middle rows</button>
</div>

Though in that specific example of yours, it doesn't seem needed. Have you tried simply not using the v-if:

<my-row v-for="position in team.positions"
            :position="position"
            :key="position.id">
</my-row>

Because the v-for just won't iterate (without throwing errors) if its value is undefined/null/0/[]/'':

new Vue({
  el: '#app',
  data: {
    message: "If I'm being displayed, Vue works!",
    team: {
      positionsU: undefined,
      positionsN: null,
      positionsZ: 0,
      positionsE: [],
      positionsS: ''
    }
  }
})
<script src="https://unpkg.com/vue"></script>

<div id="app">
  <p>{{ message }}</p>
  <table>
    <tr v-for="position in team.positionsU"><td>u: {{ position }}</td></tr>
    <tr v-for="position in team.positionsN"><td>n: {{ position }}</td></tr>
    <tr v-for="position in team.positionsZ"><td>z: {{ position }}</td></tr>
    <tr v-for="position in team.positionsE"><td>e: {{ position }}</td></tr>
    <tr v-for="position in team.positionsS"><td>s: {{ position }}</td></tr>
    <tr v-for="position in team.positionsF"><td>f: {{ position }}</td></tr>
  </table>
</div>

Upvotes: 12

mikeym
mikeym

Reputation: 6331

I am not sure if this is exactly what the original question is looking for, but I just had a similar issue where I wanted to ignore rendering rows where the price of a item was 0.

I ran into the problem using v-if in the <tr> containing the v-for. I solved it by simply using a v-show instead.

So this worked perfectly in my case.

<tr v-show="item.price !== 0" :key="item._id" v-for="item in items"> ... </tr>

Upvotes: 0

user5201343
user5201343

Reputation:

You can use v-for and v-if on the same tag, however, it works differently to how you'd expect it to.

within the v-if you can reference the iterated item since v-for is performed before v-if

<div v-if="team.positions != null">
    <my-row v-for="position in team.positions" v-if="position"
                :position="position"
                :key="position.id">
    </my-row>
</div>

this would still iterate through all positions in team.positions, and not halt the for loop if the condition in the v-if was not met, but rather skip it.

think of it like this:

for (var i = 0; i < array.length-1; i++) {
    if (array[i]) {
        doTheThing();
    }
}

Upvotes: 0

Related Questions