Search code examples
javascripthtmlvue.jsreactive-programming

In VueJS, how can you generate a component that renders a table with a fixed amount of columns and auto-distribution of cells?


Good afternoon.

I am currently working with the following VueJS component:

<template>
   <div>
     <table>
       <tbody>
         <tr v-for="(item, index) in items" :key="index">
           <td>{{ item.id }}</td>
           <td>{{ item.name }}</td>
          <td>{{ item.price }}</td>
         </tr>
       </tbody>
     </table>
   </div>
 </template>
 
 <script>
 export default {
 data() {
 return {
 items: [
 id: 1, name: "Item 1", price: 10.99 },
 id: 2, name: "Item 2", price: 20.50 },
 id: 3, name: "Item 3", price: 15.75 },
 id: 4, name: "Item 4", price: 15.75 }

      ]
     };
   }
 };
 </script>

I would like to modify the behavior of said table. I am trying to force that the table has a total of 3 columns. The table cells should be filled from left to right and from top to bottom (always ensuring that there are 3 columns).

For example, considering the variable "items" defined above, the table should look as shown below:

--------------------------------
| Item 1 | Item 2 | Item 3 |
| Item 4 |
----------------------------

I tried to use "v-if" and "v-for" directives to accomplish this, but I can't quite understand how to make this "reactive" (independent of the number of elements of the list). I find it a bit confusing to force only 3 elements per row.

How could I accomplish this?

Thank you very much for your attention.

Best regards.

The expected result should be a table like the one provided above.


Solution

  • As mentioned in my comment, don't use a table as you no longer have tabular data.

    Use CSS grid and style for as many columns as you want. You can even use CSS Media Queries to adjust columns based on device width, which is much easier to do with grid that it is with columns.

    Here's a quick functional demo

    Code :

    <script setup>
    import { ref } from 'vue'
    
    const msg = ref('Hello World!')
    const items = [
     {id: 1, name: "Item 1", price: 10.99 },
     {id: 2, name: "Item 2", price: 20.50 },
     {id: 3, name: "Item 3", price: 15.75 },
     {id: 4, name: "Item 4", price: 15.75 }]
    </script>
    
    <template>
    
     <div>
         <ul id="items">
             <li v-for="(item, index) in items" :key="index">
              <span class="id">Id: {{ item.id }}</span>
              <h2 class="name">{{ item.name }}</h2>
              <span class="price">{{ item.price }}</span>
             </li>
         </ul>
       </div>
    
    </template>
    <style>
      #items{
        list-style: none; 
        padding: 0;
        /* Make a grid */
        display: grid;
        /*Make it 3 columns */
        grid-template-columns: 1fr 1fr 1fr;
        grid-gap: 1em;
      }
    
      #items li {border: 1px solid black ;
      padding: 3px;
      }
      
      #items li .name{  
        text-align: center
      }
    
      #items li .price:before{  
        content: "$";
        display:inline-block;
    }
    
    </style>