Solution 1 :

The problem is the outer v-for was put on <tbody>, so each row was rendered with a new <tbody>:

<table class="tbl">
  <thead>
    <tr><th>Field 1</th><th>Field 2</th></tr>
  </thead>
  <tbody> <!-- row -->
    <tr><td>data11</td><td>data12</td></tr>
  </tbody>
  <tbody> <!-- row -->
    <tr><td>data21</td><td>data22</td></tr>
  </tbody>
</table>

So tbody tr:nth-child(even) would never match because each <tbody> has only one <tr>.

Solution

Put the outer v-for on the <tr> instead of <tbody>:

<table>
  <tbody>
      
    <tr v-for="row in tableData.rows">
      <td v-for="colName in tableData.columnsNames">{{ row[Object.keys(colName)[0]] }}</td>
    </tr>
  </tbody>
</table>

demo

Solution 2 :

You can try with js instead of css:

new Vue({
  el: "#demo",
  data() {
    return {
      tableData: {'columnsNames': [{"field1": "Field 1"}, {"field2": "Field 2"}, {"field3": "Field 3"}, {"field4": "Field 4"}], 'rows': [{"field1": "data11", "field2":"data12", "field3":"data13", "field4":"data14"}, {"field1": "data21", "field2":"data22", "field3": "data23", "field4":"data24"},]}
    }
  },
  methods: {
    //   find out if index of row is even
    isEven(num) {
      return (num % 2) == 0;
    }
  }
})
.tbl {
  border-collapse: collapse;
  margin: 20px 0 0 20px;
  font-size: 1em;
  font-family: Poppins;
  min-width: 400px;
  box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
}
.tbl thead tr {
  background-color: #980000;
  color: #ffffff;
  text-align: left;
}
.tbl th,
.tbl td {
    padding: 6px 10px;
    text-align: center;
}
.tbl tbody tr {
    border-bottom: 1px solid #dddddd;
}

.even {
  background-color: #f3f3f3;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
  <table class="tbl" ref="thisTable">
    <thead>
      <tr>
        <th v-for="(columnName, i) in tableData.columnsNames" :key="i"> {{Object.values(columnName)[0]}} </th>
      </tr>
    </thead>
    <tbody v-for="(row, idx) in tableData.rows" :key="idx">
      <tr>
                <!--   call method and attach class -->
        <td :class="!isEven(idx) ? 'even' : ''" v-for="(colName, i) in tableData.columnsNames" :key="i">{{ row[Object.keys(colName)[0]] }}</td>
      </tr>
    </tbody>
  </table>
</div>

Problem :

I want to change the background color of even rows in a HTML table. This was working when I had a table with known column names and one v-for for rows, but now I have unknown columns and rows so I have to do a double v-for and I can’t get it done with my previous approach.

HTML:

<template>
  <table class="tbl" ref="thisTable">
    <thead>
      <tr>
        <th v-for="columnName in tableData.columnsNames"> {{Object.values(columnName)[0]}} </th>
      </tr>
    </thead>
    <tbody v-for="row in tableData.rows">
      <tr>
        <td v-for="colName in tableData.columnsNames">{{ row[Object.keys(colName)[0]] }}</td>
      </tr>
    </tbody>
  </table>
</template>

CSS

<style scoped>
  .tbl {
    border-collapse: collapse;
    margin: 20px 0 0 20px;
    font-size: 1em;
    font-family: Poppins;
    min-width: 400px;
    box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
  }
  .tbl thead tr {
    background-color: #980000;
    color: #ffffff;
    text-align: left;
  }
  .tbl th,
  .tbl td {
      padding: 6px 10px;
      text-align: center;
  }
  .tbl tbody tr {
      border-bottom: 1px solid #dddddd;
  }
  .tbl tbody tr:nth-child(even) {
      background-color: #f3f3f3;
  }
</style>

tableData structure:

{'columnsNames': [{"field1: "Field 1"}, {"field2: "Field 2"}], 'rows': [{"field1: "data11", "field2:"data12"}, {"field1: "data21", "field2:"data22"}]}

Comments

Comment posted by Oliver Mohr Bonometti

Marked as solution. Does the job without the need of extra javascript code.

By