skip to Main Content

i want to create a line with total from each group of items in a list like this:

Model

So i did this to group by Car:

if (val == 2) {
  this.dadosResumo.sort((a, b) => (a.carro > b.carro ? 1 : -1))

and i’m using v-data-table to render the itens from dadosResumo.

but idk how to create a line in each group with the totals.

the list:

[
 carro: '11016', number: '1', quantity: '4', total: '2'},
 carro: '11016', number: '2', quantity: '3', total: '4'},
 carro: '1122', number: '2', quantity: '4', total: '5'},
 carro: '1122', number: '1', quantity: '1', total: '4'},
 carro: '1133', number: '1', quantity: '2', total: '3'}, 
]

i tried to create an map to add line with if but not worked.


EDITED

i was thinking and the best way that i saw is to put the Subtotal inside the list, like this, because i use the list to create an pdf, anyway to create an map to add the subtotal inside?
the list should be:

[
     {carro: '11016', number: '1', quantity: '4', total: '2'},
     {carro: '11016', number: '2', quantity: '3', total: '4'},
     **{carro: 'Subtotal', number: '', quantity: '7', total: '6'},**
     {carro: '1122', number: '2', quantity: '4', total: '5'},
     {carro: '1122', number: '1', quantity: '1', total: '4'},
     **{carro: 'Subtotal', number: '', quantity: '5', total: '9'},**
     {carro: '1133', number: '1', quantity: '2', total: '3'}, 
     **{carro: 'Subtotal', number: '', quantity: '2', total: '3},**
]

2

Answers


  1. First you should calculate all ‘Subtotal’ and put it in a list with the car code (for example i call ListSubtotal), then create an inner sublist according to the car code of the outer list:

    #List Subtotal
        For( var x in ListSubtotal) { 
          if(Car == x.car)
             render all child in here
    }
    
    Login or Signup to reply.
  2. This is somewhat hard to do with v-data-table. Not just writing the code so that it looks like in your image after load, but also to have it keep making sense when you interact with the table.

    For example, the table in the image seems to be sorted by car – if I sort by date, where would the subtotals go? Or if I filter the table, should the subtotals recalculate without the filtered rows?

    If it does not make sense to interact with the table that way and you’ll disable sorting, filtering, pagination anyway, I am going to go ahead and say you will be better off with a v-simple-table (or v-table in Vuetify 3). It will give you more flexibility for sacrificing functionality you don’t need. It is pretty straight-forward then:

    new Vue({
      el: '#app',
      vuetify: new Vuetify(),
      data: {
        items: [
         {carro: '11016', number: '1', quantity: '4', total: '2'},
         {carro: '11016', number: '2', quantity: '3', total: '4'},
         {carro: '1122', number: '2', quantity: '4', total: '5'},
         {carro: '1122', number: '1', quantity: '1', total: '4'},
         {carro: '1133', number: '1', quantity: '2', total: '3'}, 
        ]
      },
      computed: {
        itemsWithTotal() {
          const list = []
          let sum = 0
          for(let i = 0; i < this.items.length; i++){
            const item = this.items[i]
            list.push({type: 'item', ...item, id: list.length})
            sum += Number(item.total)
            if(item.carro !== this.items[i+1]?.carro){
              list.push({type: 'subtotal', sum, id: list.length})
              sum = 0
            }
          }
          return list
        }
      }
      
    })
    tr.subtotal{
      background: grey;
      color: white;
    }
    <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
    </head>
    
    <body>
      <div id="app">
        <v-app>
          <v-main>
          <v-simple-table>
            <template v-slot:default>
            <thead>
              <tr>
                <th class="text-left">Car</th>
                <th class="text-left">Number</th>
                <th class="text-left">Quantity</th>
                <th class="text-left">Total</th>
    
              </tr>
            </thead>
            <tbody>
              <tr v-for="(car, index) in itemsWithTotal" :key="car.id" :class="car.type">
                <template v-if="car.type==='item'">
                  <td>{{car.carro}}</td><td>{{car.number}}</td><td>{{car.quantity}}</td><td>{{car.total}}</td>
                </template>
                <template v-else>
                <td colspan="3">Subtotal</td><td>{{car.sum}}</td>
                </template>
              </tr>
            </tbody>
            </template>
    </v-simple-table>
           
          </v-main>
        </v-app>
      </div>
    
      <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js"></script>

    If you do want to use v-data-table, I think you have two options:

    1. Use a grouping with a grouping summary slot and live with the awkwardness grouping introduces (i.e. grouping column is removed from table, changes to layout, weird "group" label in header):
    new Vue({
      el: '#app',
      vuetify: new Vuetify(),
      data: {
        headers:[
          { text: 'Car', value: 'carro'},
          { text: 'Number', value: 'number'},
          { text: 'Quantity', value: 'quantity'},
          { text: 'Total', value: 'total'},
        ],
        items: [
         {carro: '11016', number: '1', quantity: '4', total: '2'},
         {carro: '11016', number: '2', quantity: '3', total: '4'},
         {carro: '1122', number: '2', quantity: '4', total: '5'},
         {carro: '1122', number: '1', quantity: '1', total: '4'},
         {carro: '1133', number: '1', quantity: '2', total: '3'}, 
        ]
      },
      computed: {
        itemsWithId() {
          return this.items.map((item,i) => ({...item, id: i}))
        }
      }
      
    })
    .v-row-group__summary{
      background: grey!important;
      color: white;
    }
    <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
    </head>
    
    <body>
      <div id="app">
        <v-app>
          <v-main>
            <v-data-table
              :headers=headers
              :items=itemsWithId
              item-key="id"
              sort-by="carro"
              group-by="carro"
              show-group-by
            >
              <template v-slot:group.summary="{items}">
                <td :colspan="headers.length-2">Subtotal</td><td>{{ items.reduce((s,i) => s+Number(i.total),0) }}</td>
              </template>
            </v-data-table>
           
          </v-main>
        </v-app>
      </div>
    
      <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js"></script>
    1. Override the item slot and define how rows are rendered manually. I think you could pretty much put in the code from the simple table above. But then you have to make sure the table functionality (pagination, filtering, sorting) works in a reasonable way.

    Does that make sense? Does one of the options work for you?

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search