Working on an E-commerce app would definitely require you to sum up the card items at some point. While the logic to do that isn’t rocket science, many of us struggle doing that for various reasons. Calculating price, subtotal, total and auto-updating them when you update a particular item can be a bit confusing. The customer can either update the quantity, description and in some cases, the price as well. That is when you need to auto calculate the total amount. In this tutorial, I’ll be showing you how to do that without using any external library. Let’s begin.
Here’s the single component code I’ve written that does the magic, I’ll explain the code in a bit:
<template>
<div id="app">
<div v-if="productItems && productItems.length">
<table>
<tr>
<th>Product</th>
<th>Quantity</th>
<th>Price</th>
<th>Amount</th>
<th>Action</th>
</tr>
<tr v-for="(product, i) in productItems" :key="i">
<td>
<input type="text" placeholder="Name" v-model="product.name" />
</td>
<td>
<input
type="number"
placeholder="Quantity"
v-model.number="product.quantity"
@change="updateProductItem(product)"
/>
</td>
<td>
<input
type="number"
placeholder="Price"
v-model.number="product.price"
@change="updateProductItem(product)"
/>
</td>
<td>${{ product.amount }}</td>
<td @click="removeProductAt(i)" class="np-remove-btn">Remove</td>
</tr>
</table>
<div class="np-items-total">
Total amount: <strong>${{ totalItemsAmount }}</strong>
</div>
</div>
<div class="np-new-item-desc">
<div class="np-new-item-head"><strong>Add new product</strong></div>
<table>
<tr>
<th>Product</th>
<th>Quantity</th>
<th>Price</th>
<th>Amount</th>
</tr>
<tr>
<td>
<input type="text" placeholder="Product name" v-model="itemName" />
</td>
<td>
<input
type="number"
placeholder="Quantity"
v-model.number="itemQuantity"
/>
</td>
<td>
<input
type="number"
placeholder="Price"
v-model.number="itemPrice"
/>
</td>
<td>${{ itemQuantity * itemPrice }}</td>
</tr>
</table>
<div @click="addNewProduct()" class="np-add-item-btn">Add</div>
</div>
<div class="np-credits">www.nightprogrammer.com</div>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
itemName: null,
itemQuantity: 0,
itemPrice: 0,
itemAmount: 0,
productItems: [],
totalItemsAmount: 0,
};
},
methods: {
addNewProduct() {
this.itemName &&
this.itemQuantity &&
this.itemPrice &&
this.productItems.push({
name: this.itemName,
quantity: this.itemQuantity,
price: this.itemPrice,
amount:
parseFloat(Number(this.itemQuantity)) *
parseFloat(Number(this.itemPrice)),
});
this.itemName = null;
this.itemQuantity = this.itemPrice = 0;
this.updateTotalAmount();
},
updateProductItem(product) {
product.amount = product.quantity * product.price;
this.updateTotalAmount();
},
updateTotalAmount() {
this.totalItemsAmount = 0;
this.productItems.forEach((item) => {
this.totalItemsAmount += item.amount;
});
},
removeProductAt(productIndex) {
this.productItems = this.productItems.filter((p, i) => {
return i !== productIndex;
});
},
},
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
input {
border: 1px solid #a389ad;
font-size: 14px;
padding: 4px 8px;
outline: none;
border-radius: 4px;
transition: all 0.3s;
}
input:hover {
border: 1px solid #a389ad;
font-size: 14px;
padding: 4px 8px;
outline: none;
border-radius: 4px;
transition: all 0.3s;
}
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 100%;
}
td,
th {
border: 1px solid #a389ad;
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #e6d7ec;
}
.np-new-item-desc {
margin-top: 20px;
padding: 4px;
border: 1px solid #e6d7ec;
max-width: 720px;
}
.np-new-item-head {
padding: 8px 0px 12px 0px;
}
.np-add-item-btn {
width: 80px;
background: #7a3097;
text-align: center;
color: #ffffff;
padding: 4px;
font-size: 14px;
border-radius: 4px;
margin: 12px 0px 8px 0px;
cursor: pointer;
}
.np-items-total {
margin-top: 12px;
font-weight: 600;
}
.np-remove-btn {
cursor: pointer;
color: #6b0f0f;
}
.np-credits {
font-size: 12px;
margin-top: 12px;
}
</style>
Code language: HTML, XML (xml)
On line 4, I’ve created a table to show a list of added product items. I’ve iterated over the items on line 12. Through line 41 to 72, I’ve created the view to add a new product item to the items list. itemName, itemQuantity and itemPrice states keep the data of a newly added added. When you click on ‘Add’, addNewProduct() method on line 91 gets called. There, you’d notice that I’ve manually updated the amount of the product by multiplying the given price and quantity. I’ve also called the updateTotalAmount() method at line 105. This method updates the total amount (auto calculates the total amount by iterating over and summing all the items prices) which I’ve displayed on line 37.
You’d also notice that I’ve called the updateTotalAmount() method whenever there’s a change in quantity or price of an already added item. Line 21 and 29 are calling this method respectively.
This is how the view should look like:
And of course, you can find a working version of the above code from my repos here to understand better: