2

I'm quite new to coding (less than 3months old) and I'm currently trying to learn vue. I'm trying out this simple exercise of doing a basic shopping cart and I want to get the total of all the product amounts. Here is my code:

HTML

<template>
<div class="product" @click="isMilkshown = true">{{ productList[0].name }}&nbsp;&nbsp;&nbsp;$ {{ productList[0].amount }}</div>
<div class="product" @click="isFishshown = true">{{ productList[1].name }}&nbsp;&nbsp;&nbsp;$ {{ productList[1].amount }}</div>
<div class="product" @click="isLettuceshown = true">{{ productList[2].name }}&nbsp;&nbsp;&nbsp;$ {{ productList[2].amount }}</div>
<div class="product" @click="isRiceshown = true">{{ productList[3].name }}&nbsp;&nbsp;&nbsp;$ {{ productList[3].amount }}</div>

<!-- Cart -->
<div class="main-cart">
 <div>Cart</div>
 <div class="main-cart-list" v-for="product in productList" :key="product">
  <div v-if="showProduct(product.name)">{{ product.name }}&nbsp;&nbsp;&nbsp;$ {{ product.amount }}</div>
 </div>
 <div>Total: 0</div>
</div>
</template>

JS

export default {
data() {
 return {
  productList: [
    { name: "Milk", amount: 10 },
    { name: "Fish", amount: 20 },
    { name: "Lettuce", amount: 5 },
    { name: "Rice", amount: 2.5 }
  ],

  isMilkshown: false,
  isFishshown: false,
  isLettuceshown: false,
  isRiceshown: false
}
},

methods: {
  showProduct(name) {
    if (name === "Milk" && this.isMilkshown === false) {
    return false
   } else if (name === "Fish" && this.isFishshown === false) {
    return false
   } else if (name === "Lettuce" && this.isLettuceshown === false) {
    return false
   } else if (name === "Rice" && this.isRiceshown === false) {
    return false
   } else {
    return true
   }
  }
 }
}

I want to replace the "zero" in Total with the sum of all the product amounts when a product is clicked. Hope someone can help me, thanks!

maxshuty
  • 9,708
  • 13
  • 64
  • 77
7even
  • 21
  • 1
  • To sum up an array of numeric values in JS you can use `arr.reduce((a, b) => a + b)`. If any of them is not a number you might get `NaN` as a result. – tao Apr 07 '21 at 12:08
  • The problem with the way you're using Vue is that you mixed up UI, business and data logic. The goal is not to write a cart that only works with 4 specific products, but one which works with any products (without caring what they are). The ideal would be to write a cart which could be injected into another project and still work. So props like `isRiceShown` and `isLettuceShown` should be avoided. Replace them with a boolean `isVisible` property on each cart item. – tao Apr 07 '21 at 13:02
  • Thanks for the input, I'll try your suggestions out. – 7even Apr 12 '21 at 05:56

1 Answers1

1

You would use a computed function.

https://v2.vuejs.org/v2/guide/computed.html

In Vue, computed functions watch all the reactive variables referenced within them and re-run to update the returned value when any of those variables change.

Simply create a computed function that loops over each productList item and sums up the amount then returns it.

You can reference this answer to learn how to sum using reduce or for a standard example with a loop Better way to sum a property value in an array

Also, you can use a v-for loop on your

<div class="product" @click="isMilkshown = true">{{ productList[0].name }}&nbsp;&nbsp;&nbsp;$ {{ productList[0].amount }}</div>

component so that you don't have duplicated code:

<div v-for="item in productList" key="item.name" class="product">{{ item.name }}&nbsp;&nbsp;&nbsp;$ {{ item.amount }}</div>

This would create one of each of those elements for each item in your productList variable.

You would then need to re-write the click handler to be dynamic too.

Lastly, you can also convert your big if/else-if chained method into a computed function too so that you watch for changes in that.

To do that, you'd make the computed return an object like this:

{
    Milk: true,
    Fish: false
    ...
}

You can put the key as the name so that in your loop you can reference the computed property like this enabledItems[item.name] to get the true/false.

tony19
  • 125,647
  • 18
  • 229
  • 307
Jordan
  • 2,245
  • 6
  • 19