Vue table in one loop html

18.7k views Asked by At

I have an array, with sizes of shoes and quantity each of them in shop, structure like this:

array = {
    36=>1,   
    37=>0,
    38=>5,
    39=>2
}

In my table key in this table ( here 36, 37 ... ) are TH, and value is TD. I can't do this in one loop. I tried like this:

<table class="table">
    <tr>
        <th v-for="(quantity, key) in productSizes" :key='key'>{{key}}</th>
    </tr>

    <tr>
    <td>Here should be quantity for each size<td>
    </tr>

</table>

Is there a possibility to do this at once?

Here is structure how it should look like (there is an input, because someone can change quantity).

enter image description here

2

There are 2 answers

0
Bert On BEST ANSWER

I cannot conceive of a way you could do this in one loop, nor do I think it's worth the effort. Just loop a second time over the same data structure and you will always get matching columns.

console.clear()

const shoeSizes = {
  36: 0,
  37: 2,
  38: 1,
  39: 3,
  40: 2,
  41: 0
}

new Vue({
  el: "#app",
  data:{
    shoeSizes
  }
})
<script src="https://unpkg.com/[email protected]"></script>
<div id="app">
  <table>
    <tr>
      <th v-for="quantity, key in shoeSizes">{{key}}</th>
    </tr>
    <tr>
      <td v-for="quantity, key in shoeSizes">
        <input type="text" v-model="shoeSizes[key]">
      </td>
    </tr>
  </table>
</div>

Assuming there were even 100 shoe sizes the performance impact would be negligible.

Edit

Well, I can think of one way you could render it in one loop. Using a render function.

console.clear()

const shoeSizes = {
  36: 0,
  37: 2,
  38: 1,
  39: 3,
  40: 2,
  41: 0
}

new Vue({
  el: "#app",
  data:{
    shoeSizes
  },
  render(h){
    let headers = [], cells = []
    // build the headers and cells
    for (let key of Object.keys(this.shoeSizes)){
      // header is easy
      headers.push(h('th', key))
      
      // build props for the input to implement v-model
      let vmodel = {
        domProps: {
          value: this.shoeSizes[key]
        },
        on: {
          input: event => {
            this.$set(this.shoeSizes, key, event.target.value) 
            this.$emit('input', event.target.value)
          }
        }
      }
      // add the vell
      cells.push(h('td', [h('input', vmodel)]))      
    }
    // render the table with headers and cells in the 
    // right places
    return h('table', [h('tr', headers), h('tr', cells)])
  }
})
<script src="https://unpkg.com/[email protected]"></script>
<div id="app"></div>

This render function builds the headers and cells in the same loop and then renders the table around them. But I think you would agree this is needlessly complex.

1
coolspeedway On

I believe the right way to do it would be to use a template. I have not tested the code personally but it would seem like the right way to do it.

Similar example found here

<tbody>
<template v-for="(quantity, key) in productSizes" :key='key'>
    <tr>
        <th>{{key}}</th>
    </tr>
    <tr>
        <td>{{key}}<td>
    </tr>
</template>
</tbody>

Edit

Made it work with a single v-for loop using above example (had time to test it this time).

const productSizes = {
  36: 0,
  37: 2,
  38: 1,
  39: 3,
  40: 2,
  41: 0
}

new Vue({
  el: "#app",
  data:{
    productSizes
  }
})
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>

<div id="app">
  <table>
    <tbody>
      <template v-for="(quantity, key) in productSizes">
          <tr>
              <th>{{key}}</th>
          </tr>
          <tr>
          <td><input v-model="productSizes[key]" type="text"><td>
          </tr>
      </template>
    </tbody>
  </table>
</div>