1

I'm trying to populate rows in an HTML table using the Vue framework - the data is as seen below:

TeamRows: [
            { team: 'One', times: ['1', '2', '3'] },
            { team: 'Two', times: ['4', '5', '6'] },
            { team: 'Three', times: ['7', '8', '9'] }
          ]

I've tried following this codepen, but with bad result - this is my HTML:

<tbody>
   <tr v-for="(row, rindex) in teamRows">
      <td>{{rindex}}</td>
         <template>
            <cell v-for="(value, vindex) in row" :value="value" :vindex="vindex" :rindex="rindex"></cell>
         </template>
   </tr>
</tbody>
</table>
<template id="template-cell">
   <td>{{ value }}</td>
</template>

And this is the Vue component:

Vue.component('cell', {
    template: '#template-cell',
    name: 'row-value',
    props: ['value', 'vindex', 'rindex']
});

I would like the team to go in the first column in a row and the times to follow along in as many columns as there are times. Hope someone with more Vue knowledge is able to help me out here. Cheers.

8
  • 2
    If you don't use a cell component here it works fine: jsfiddle.net/wostex/63t082p2/81 Looks like the issue arises only when you're trying to loop components - it throws an error row is not defined during render. I've never encountered this to be honest, maybe someone from Vue team can clarify this (@Linus Borg ?). Also you have strange <template> wrapper for whatever reason, I don't think it's needed. Commented Jul 5, 2017 at 11:19
  • Because it's an in DOM template, that whole section between template tags in the table will be yanked out of the table by most browsers before Vue even compiles the template (because it is invalid HTML). Then, Vue will compile the template and will try to iterate over row, which no longer exists. Commented Jul 5, 2017 at 11:32
  • @wostex That worked like a charm. I only used the cell and <template> due to that codepen. Yours is simpler and it actually works. Thanks a bunch! If you post it as an answer, I can mark it as solved if you'd like. Commented Jul 5, 2017 at 11:33
  • @BertEvans I don't get it. Here's an example: jsfiddle.net/wostex/63t082p2/82 there's an error. There's no template tag or whatever. In my own code I'm using nested v-for with components no problem for some reason (though I don't see a difference). What is actually broken in this code? Commented Jul 5, 2017 at 12:02
  • 2
    @wostex Check out this updated fiddle. I removed Vue so you can see what the browser actually renders (you can inspect it). Notice cell is moved. Browsers are very picky about what they will allow inside certain HTML like tables. It is one of the reasons the is directive exists. Commented Jul 5, 2017 at 12:10

1 Answer 1

4

Turns out the reason is you're using in-DOM template and browser moves unknown cell element above the v-for, and Vue can't access row value anymore: https://v2.vuejs.org/v2/guide/components.html#DOM-Template-Parsing-Caveats

A solution without cell component, just with inline cell elements, works fine. Also, template wrapper is not needed in a table template:

new Vue({
  el: '#app',
  data: {
    teamRows: [
      { team: 'One', times: ['1', '2', '3'] },
      { team: 'Two', times: ['4', '5', '6'] },
      { team: 'Three', times: ['7', '8', '9'] }
    ]
  }
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>

<div id="app">
  <table>
    <tbody>
     <tr v-for="row in teamRows" :key="row.team">
       <td>{{ row.team }}</td>
       <td v-for="time in row.times">{{ time }}</td>
     </tr>
    </tbody>
  </table>
</div>

Also, as a result of a discussion, you can still use a component if you wrap your table into another component for example, so that browser don't interfere and Vue has a chance to render everything properly:

new Vue({
  el: '#app',
  data: {
    teamRows: [
      { team: 'One', times: ['1', '2', '3'] },
      { team: 'Two', times: ['4', '5', '6'] },
      { team: 'Three', times: ['7', '8', '9'] }
    ]
  }, 
  components: {
    'mytable': {
      template: `<table>
    <tbody>
     <tr v-for="row in rows" :key="row.team">
       <td>{{ row.team }}</td>
       <cell v-for="time in row.times" :value="time" :key="time"></cell>
     </tr>
    </tbody>
  </table>`,
      props: ['rows'],
      components: {
        'cell': {
          template: `<td>{{ value }}</td>`,
          props: ['value'],
        }
      }
    }
  }
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>

<div id="app">
  <mytable :rows="teamRows"></mytable>
</div>

Sign up to request clarification or add additional context in comments.

1 Comment

I commented above why the cell component breaks. You could also use <td is="cell" ...></td>.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.