I have completed this mockup eCommerce app using pure Vanilla Javascript. This version can add product into shopping cart and automatically calculate the order summary in the shopping cart. It can also delete one item and all items in the shopping cart.
Certain function like checkout,payment,login,update quantity in cart are not included.
Known bugs are duplicate item will be still added when you add same product into cart.
Appreciate all comments and code review especially on Javascript and coding style and best practices. Thanks a lot in advance.
// Bugs
// 1. If a product already added into shopping cart, and add again.
// there will be duplicate.
var productList = [
{ id: 101, product: "Logitech Mouse", unitprice: 45.0 },
{ id: 102, product: "Logitech Keyboard", unitprice: 50.0 },
{ id: 103, product: "HP Mouse", unitprice: 35.0 },
{ id: 104, product: "HP Keyboard", unitprice: 32.0 },
{ id: 105, product: "Microsoft Mouse", unitprice: 43.0 },
{ id: 106, product: "Microsoft Keyboard", unitprice: 39.0 }
];
var cart = [];
const createCartHTMLElements = object => {
// Check type
if (typeof object !== "object") return false;
// Start our HTML
var html =
"<table><tbody><tr>\
<td>Product</td>\
<td>Price</td>\
<td>Unit</td>\
<td>Total</td>\
<td></td></tr>";
// Loop through members of the object
object.forEach(function(item) {
html += `<tr><td>${item.product}</td>\
<td>${item.unitprice.toFixed(2)}</td>\
<td><button>+</button>${item.quantity}<button>-</button></td>\
<td>${item.total.toFixed(2)}</td>\
<td><i class="fa fa-remove del" data-id="${item.id}"></i></td>\
</tr>`;
});
// Finish the table:
html += "</tbody></table>";
// Return the table
return html;
};
document.getElementById("clearAll").addEventListener(
"click",
function() {
document.getElementById("shoppingCart").innerHTML = "";
cart.length = 0;
document.getElementById("clearAll").style.display = "none";
document.getElementById("summary").style.display = "none";
updateOrderSummary();
},
false
);
// false means preventdefault.
// sometimes by default, it will trigger other thing
const populateProducts = arrOfObjects => {
// Start our HTML
var html = "";
// Loop through members of the object
arrOfObjects.forEach(function(item) {
html += `<div class="column"><div class="card">\
<h2>${item.product}</h2>
<p class="price">RM ${item.unitprice.toFixed(2)}</p>
<p><button class=AddToCart data-id="${
item.id
}">Add to Cart</button></p>\
</div></div>`;
});
return html;
};
const updateOrderSummary = () => {
//if (cart.length > 0) {
document.getElementById("totalItem").innerHTML = cart.length + " item";
const subTotal = cart
.reduce(function(acc, obj) {
return acc + obj.total;
}, 0)
.toFixed(2);
const shippingFee = 10;
document.getElementById("subTotal").innerHTML = subTotal;
document.getElementById("shippingFee").innerHTML = shippingFee.toFixed(2);
document.getElementById("total").innerHTML = (
parseInt(subTotal) + shippingFee
).toFixed(2);
//}
};
window.addEventListener("load", function() {
document.getElementById("shoppingCartContainer").style.display = "none";
window.setTimeout(function() {}, 1000); // prevent flickering
document.getElementById("productRow").innerHTML = populateProducts(
productList
);
var addToCart = document.getElementsByClassName("AddToCart");
Array.prototype.forEach.call(addToCart, function(element) {
element.addEventListener("click", function() {
debugger;
// Filter the selected "AddToCart" product from the ProductList list object.
// And push the selected single product into shopping cart list object.
productList.filter(prod => {
if (prod.id == element.dataset.id) {
prod.quantity = 1;
prod.total = prod.unitprice;
cart.push(prod);
document.getElementById(
"shoppingCart"
).innerHTML = createCartHTMLElements(cart);
CreateDeleteEventListener();
document.getElementById("clearAll").style.display = "block";
document.getElementById("summary").style.display = "block";
updateOrderSummary();
return;
}
});
});
});
function CreateDeleteEventListener() {
var del = document.getElementsByClassName("del");
Array.prototype.forEach.call(del, function(element) {
element.addEventListener("click", function() {
debugger;
console.log(element.dataset.id);
cart = cart.filter(function(el) {
return el.id != element.dataset.id;
});
if (cart.length === 0) {
document.getElementById("shoppingCart").innerHTML = "";
debugger;
document.getElementById("clearAll").style.display = "none";
document.getElementById("summary").style.display = "none";
}
updateOrderSummary();
element.closest("tr").remove();
});
});
}
});
document.getElementById("cartIcon").addEventListener("click", function() {
var x = document.getElementById("shoppingCartContainer");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
});
.card {
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
margin: auto;
text-align: center;
font-family: arial;
width: 18em;
}
.price {
color: grey;
font-size: 1.5em;
}
.card button {
border: none;
outline: 0;
padding: 12px;
color: white;
background-color: #000;
text-align: center;
cursor: pointer;
width: 100%;
font-size: 1em;
}
.card button:hover {
opacity: 0.7;
}
.some-page-wrapper {
margin: 15px;
}
.summaryDetails {
width: 100px;
text-align: right;
}
#productRow {
display: flex;
flex-wrap: wrap;
}
.column {
flex: 1;
margin-top: 12px;
}
@media (max-width: 1333px) {
.column {
flex-basis: 33.33%;
}
}
@media (max-width: 1073px) {
.column {
flex-basis: 33.33%;
}
}
@media (max-width: 815px) {
.column {
flex-basis: 50%;
}
}
@media (max-width: 555px) {
.column {
flex-basis: 100%;
}
}
#header {
width: 100%;
display: flex;
justify-content: space-between;
height: 50px;
}
#left,
#right {
width: 30%;
padding: 10px;
}
#right {
text-align: right;
}
#main {
max-width: 1000px;
border: 1px solid black;
margin: 0 auto;
position: relative;
}
#shoppingCartContainer {
width: 300px;
background-color: lightyellow;
border: 1px solid silver;
margin-left: auto;
position: absolute;
top: 50px;
right: 0;
padding: 10px;
}
.fa-shopping-cart {
font-size: 36px;
color: blue;
cursor: pointer;
}
.fa-remove {
font-size: 24px;
color: red;
cursor: pointer;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
/>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="main">
<div id="header">
<div id="left">Login as Joe Doe, <a href="">Logout</a></div>
<div id="right">
<i id="cartIcon" class="fa fa-shopping-cart"></i>
</div>
</div>
<hr />
<div class="some-page-wrapper">
<div id="productRow"></div>
</div>
<div id="shoppingCartContainer">
<div id="shoppingCart"></div>
<button id="clearAll">Clear Cart</button>
<div id="summary">
<hr />
<h3>Order Summary</h3>
<table>
<tr>
<td>Subtotal (<span id="totalItem"></span>)</td>
<td class="summaryDetails"><span id="subTotal"></span></td>
</tr>
<tr>
<td>Shipping Fee</td>
<td class="summaryDetails"><span id="shippingFee"></span></td>
</tr>
<tr>
<td>Total</td>
<td class="summaryDetails"><span id="total"></span></td>
</tr>
</table>
<button>Proceed to checkout</button>
</div>
</div>
</div>
</body>
</html>
<script src="app.js"></script>