cantdocpp
cantdocpp

Reputation: 1126

Vue: how to update cart total price when user increment item in child component

So I create this cart page in Vue. I just don't understand how to update the cart page total price when the quantity of the item child component increase or decreases. If the item component quantity increase, of course, the total price must increase too.

Here's my cart parent component :

<template>
  <div class="cart-container">
    <h1 class="cart-title-page">Keranjang Anda</h1>
    <div class="cart-item-container">
      <cart-item v-for="(data, i) in cartData" :item="data" :key="i" />
    </div>
    <div class="cart-total-wrapper">
      <div class="total-text-wrapper">
        <p>Total</p>
      </div>
      <div class="total-amount-wrapper">
        <p>Rp. 150.000.000</p>
      </div>
    </div>
  </div>
</template>

<script>
import CartItem from '@/components/cart-item'

export default {
  data() {
    return {
      cartData: [
        {
          product_name: 'vario ZS1',
          price: 1000000,
          url_thumbnail: 'https://cdn3.imggmi.com/uploads/2019/10/8/9e27ca9046031f6f21850be39b379075-full.png',
          color: '#fff'
        },
        {
          product_name: 'vario ZS1',
          price: 1000000,
          url_thumbnail: 'https://cdn3.imggmi.com/uploads/2019/10/8/9e27ca9046031f6f21850be39b379075-full.png',
          color: '#fff'
        },
        {
          product_name: 'vario ZS1',
          price: 1000000,
          url_thumbnail: 'https://cdn3.imggmi.com/uploads/2019/10/8/9e27ca9046031f6f21850be39b379075-full.png',
          color: '#fff'
        }
      ]
    }
  },
  methods: {
    getAllCartItem () {
      this.$store.dispatch('cart/checkCartItem')
      this.cartData = this.$store.state.cart.cartItem
    }
  },
  created () {
    this.getAllCartItem ()
  },
  components: {
    'cart-item': CartItem
  }
}
</script>

this is my cart item child component:

<template>
  <div class="root-cart-item">
    <div class="container-cart-left">
      <div class="cart-img-wrapper">
          <img :src="item.url_thumbnail" />
      </div>
      <div class="cart-title-wrapper">
        <div class="title-wrapper">
          <h3>{{ getProductbrand }}</h3>
          <p>{{ item.product_name }}</p>
        </div>
      </div>
    </div>

    <div class="container-cart-right">
      <div class="cart-amount-wrapper">
        <number-input v-model="singleCart.amount" :min="1" :max="singleCart.stok" inline center controls></number-input>
      </div>
      <div class="cart-price-wrapper">
        <p>{{  getProductTotalPrice  }}</p>
      </div>
      <div class="cart-delete-wrapper">
        <img src="../assets/delete.svg"/>
      </div>
    </div> 

  </div>
</template>

<script>
import ProductImage from './product-image'
import VueNumberInput from '@chenfengyuan/vue-number-input';

export default {
  props: {
    item: {
      type: Object,
      required: true
    }
  },
  data () {
    return {
      singleCart: {
        stok: 15,
        amount: 1,
        totalPrice: 0
      }
    }
  },
  computed: {
    getProductbrand: function () {
      let splittedName = this.item.product_name.split(' ')
      return splittedName[0]
    },
    getProductTotalPrice: function () {
      var x = this.singleCart.totalPrice.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".")
      var totalPrice = `Rp. ${x}`
      return totalPrice
    }
  },
  watch: {
    'singleCart.amount': {
      handler: function () {
        this.singleCart.totalPrice = this.singleCart.price * this.singleCart.amount
      },
      deep: true
    }
  },
  components: {
    'product-image': ProductImage,
    'number-input': VueNumberInput
  }
}
</script>>

and if anyone wondering, this is my cart store:

const state = {
  cartItem: []
}

const getters = {
  getAllCartItem: (state) => {
    return state.cartItem
  }
}

const mutations = {
  updateCartItem: (state, cart) => {
    state.cartItems = cart
  }
}

const actions = {
  checkCartItem: ({ commit }) => {
    let item = JSON.parse(localStorage.getItem('cart'))
    if (cart) {
      commit('updateCartItem', item)
    } 
  }
}

export default {
  namespaced: true,
  state,
  getters,
  actions,
  mutations
}

like I said, the problem should be quite simple, I just have to update the CSS class .total-amount-wrapper in the parent component, when the quantity in the child component increase or decreases. The total price in the child cart-item component is working, I just have to find a way to count every total price in the child cart-item component, and show it in the parent component.

Upvotes: 0

Views: 2972

Answers (1)

Max
Max

Reputation: 7090

For update the parent you must use the v-model approach or use the $emit.

In your code you must update the input to use the v-model or you must $emit an event when price change.

The first is simple and you must follow the tutorial you find in the link above, the second is below.

Child Component

watch: {
    'singleCart.amount': {
      handler: function () {
        this.singleCart.totalPrice = this.singleCart.price * this.singleCart.amount
        this.$emit("priceChanged", this.singleCart.totalPrice);
      },
      deep: true
    }
  }

Parent

<template>

..

 <div class="cart-item-container">
      <cart-item v-for="(data, i) in cartData" :item="data" :key="i" 
              @priceChanged="onPriceChanged" />
 </div>

</template>

<script>

methods: {
..
     onPriceChanged(value) {
         this.total += value;
     }
}


</scritp>

Upvotes: 2

Related Questions