4

I am making a shopping cart using Vuetify's current CRUD Datatable UI Component (compatible with Vue.js2). I previously had a problem to calculate the total of a product by multiplying the product's quantity with its price. Fortunately, I was given a great solution by using a computed function detailsWithSubTotal() to calculate the total and replacing the datatable's :item value (previously "details") to :item="detailsWithSubTotal" as you can see 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(detailsWithSubTotal, 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
      }))
    }
  },
  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);
        if (i!==-1){
            arr.splice(i,1);
        }
    },
  }
}
</script>

Though this helped to solve my previous problem, now I can't delete the added detail.

While keeping the array parameter in the @click event as @click="deleteDetail(details, item) and the datatable's :item value as :items="details", the delete button works with no problem, but then the subtotal calculation does not work as you can see in the following image:

enter image description here

But when replacing both array parameter to @click="deleteDetail(detailsWithSubTotal, item) and :item value to :items="detailsWithSubTotal", it calculates the subtotal but the delete button stops working.

enter image description here

How can I delete the added row on the datatable while not interfering with the detailsWithSubTotal() computed function?

DigitalDevGuy
  • 83
  • 4
  • 14
  • Inside method=`deleteDetail`, Delete the item from data property=`this.details` directly instead of delete the item from the computed property=`detailsWithSubTotal`, because `detailsWithSubTotal` is a clone for `this.details`. Check [MDN: Array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map), you will see this description: `Array.map` will create one new array – Sphinx Jun 22 '20 at 22:15

1 Answers1

1

You can try to add detail itself to a computed item as a link to an original item and use it to delete from the original details array:

detailsWithSubTotal() {
      return this.details.map((detail) => ({
        ...detail,
        subtotal: detail.quantity * detail.price,
        source: detail
      }))
    }
...
@click="deleteDetail(details, item)
...
deleteDetail(arr,item){
        var i= arr.indexOf(item.source);
        if (i!==-1){
            arr.splice(i,1);
        }
    }
Anatoly
  • 20,799
  • 3
  • 28
  • 42
  • I tried it as you said and it worked! This is just what I needed. Thank you very much! Where could I find more information that explains more about linking computed items to an original item? – DigitalDevGuy Jun 23 '20 at 02:18
  • 1
    This is just one of the approaches. Alternative one is to indicate a template for an item and calculate `sum` in `Subtotal` cell template directly. – Anatoly Jun 23 '20 at 15:14