0

I am making a shopping cart using Vuetify's current CRUD Datatable UI Component (compatible with Vue.js2), and I'm trying to add a type="number" text-field for both columns quantity and price and link them to their respective value to calculate their total.

Here you can see how it can add, calculate a total from 2 static values (which I was using temporarily to test the subtotal calculation with a computed function), and delete with no problem in the following code:

HTML:

<template>
  <v-layout align-start>
    <v-flex>
      <v-container grid-list-sm class="pa-4 white">
        <v-layout row wrap>
          <v-flex xs12 sm8 md8 lg8 xl8>
            <v-text-field v-model="code" label="Barcode" @keyup.enter="searchBarcode()">
            </v-text-field>
          </v-flex>
          <v-flex xs12 sm12 md12 lg12 xl12>
            <v-data-table 
              :headers="headerDetails" 
              :items="detailsWithSubTotal" 
              hide-default-footer 
              class="elevation-1"
            >
              <template v-slot:item.delete="{ item }">
                  <v-icon small class="ml-3" @click="deleteDetail(details, item)">
                      delete
                  </v-icon>
              </template>
              <template v-slot:no-data>
                <h3>There are no current products added on details.</h3>
              </template>
            </v-data-table>
          </v-flex>
        </v-layout>
      </v-container>
    </v-flex>
  </v-layout>
</template>

JAVASCRIPT:

<script>
import axios from 'axios'
export default {
  data() {
    return {
      headerDetails: [
        { text: 'Remove', value: 'delete', sortable: false },
        { text: 'Product', value: 'product', sortable: false },
        { text: 'Quantity', value: 'quantity', sortable: false },
        { text: 'Price', value: 'price', sortable: false },
        { text: 'Subtotal', value: 'subtotal', sortable: false }
      ],
      details: [],
      code: ''
    }
  },
  computed: {
    detailsWithSubTotal() {
      return this.details.map((detail) => ({
        ...detail,
        subtotal: detail.quantity * detail.price,
        source: detail
      }))
    }
  },
  methods: {
    searchBarcode() {
      axios
        .get('api/Products/SearchProductBarcode/' + this.code)
        .then(function(response) {
          this.addDetail(response.data)
        })
        .catch(function(error) {
          console.log(error)
        })
    },
    addDetail(data = []) {
      this.details.push({
        idproduct: data['idproduct'],
        product: data['name'],
        quantity: 10,
        price: 150
      })
    },
    deleteDetail(arr,item){
        var i= arr.indexOf(item.source);
        if (i!==-1){
            arr.splice(i,1);
        }
    },
  }
}
</script>

In the example that I've been using as a reference to build this shopping cart, he does not display the data from javascript, but from HTML using <td> and props.items as you can see in the code below:

Previous Version (this example I found is from a previous version of vue.js from 2 years old):

<template slot="items" slot-scope="props">
    <td class="justify-center layout px-0">
        <v-icon small class="ml-3" @click="deleteDetail(details, props.item)">
            delete
        </v-icon>
    </td>
    <td>{{ props.item.product }}</td>
    <td><v-text-field type="number" v-model="props.item.quantity"></v-text-field></td>
    <td><v-text-field type="number" v-model="props.item.price"></v-text-field></td>
    <td>$ {{ props.item.quantity * props.item.price }}</td>
</template>

This is how his example turns out looking:

enter image description here

While this is how my datatable looks like with my code (while using the hard-coded quantity and price values):

enter image description here

Since I'm not using any <td> or any props, how can I implement a text-field in the datatable and link them to their value for it to be able to calculate the product total?

DigitalDevGuy
  • 83
  • 4
  • 14

1 Answers1

2

You just need to add template inside the table tags just like what you did with the delete icon, You need to make sure that it has it's v-slot named just like the header you want to place the text field under it.

<v-layout align-start>
  <v-flex>
    <v-container grid-list-sm class="pa-4 white">
      <v-layout row wrap>
        <v-flex xs12 sm8 md8 lg8 xl8>
          <v-text-field v-model="code" label="Barcode" @keyup.enter="searchBarcode()">
          </v-text-field>
        </v-flex>
        <v-flex xs12 sm12 md12 lg12 xl12>
          <v-data-table
            :headers="headerDetails"
            :items="detailsWithSubTotal"
            hide-default-footer
            class="elevation-1"
          >
            <template v-slot:item.delete="{ item }">
              <v-icon small class="ml-3" @click="deleteDetail(details, item)">
                delete
              </v-icon>
            </template>
            <template v-slot:item.quantity="{ item }">
              <v-text-field v-model="item.quantity">
                
              </v-text-field>
            </template>

            <template v-slot:no-data>
              <h3>There are no current products added on details.</h3>
            </template>
          </v-data-table>
        </v-flex>
      </v-layout>
    </v-container>
  </v-flex>
</v-layout>

The result of the code looks like that: screenshot

Mostafa Labib
  • 789
  • 6
  • 17
  • This works perfectly! Not only did you give me a solution, but thanks to you I've learned something that has been giving me trouble to adapt my code from many examples from older versions of Vue.js. I know it sounds basic, but have been giving me a headache for the past week since I'm not using them at all. I'm starting to learn vue.js, and this will definitely help me solve many problems (as simple as they may seem or not). Thank you very much! – DigitalDevGuy Jun 24 '20 at 01:08