Shopping cart in Vanilla Js

Frequently asked interview question for front-end development.

Ā·

5 min read

It's very important to learn JavaScript well before jumping into any of the frameworks i.e. React, Angular, Vue, etc.

The best way to learn and get proficient in JavaScript is to build some random small apps frequently and that's how you'll get the hang of it. However, I recently got the task to build a shopping cart.

So, here is the documentation of how I solved it which can be beneficial for you as well.

So Let me briefly discuss the task first ->

image.png

Functionality to be implemented:-

  1. The website/app should retrieve product data from the API endpoint mentioned and render the cart interface depicted in the image.

2) Update the quantity of a product. (This should reflect in the price details card on the right)

3) Remove a product (This should reflect in the price details card as well).

4) The UI should closely resemble the design.

Let's dive in guys!!

giphy.gif

I have always learned that It's always good to make the app structure and design before getting to code the functionalities and solving that particular problem.

So, I mostly used flex for designing the whole page and sections of it. I won't take much time in explaining how I designed it as the discussion is more about Js.

This is how my app looked:-

image.png

To be brief, I used flex-row to display My Cart() and Price Details section in a row. Then I again used flex-row to display -> Product Image, Product details(name, seller name, price, discount & offers), and delivery details. Coming to quantity counter, SAVE FOR LATER & REMOVE Button, Have used a separate div below product Image.

That's all about how I approached designing this page.

But. But. But. the HTML code is not directly coming from the index.html. Had to fetch product data from the API given.

The HTML file just has the basic div's wherein, data is not coming from API:-

index.html

<body>
    <div class="page-grids">
        <div class="cart-div">
            <div class="cart-heading"></div>

            <!-- Product card -->
            <div class="product-cart-1"></div>
            <div class="place-order">
                <button class="order-btn">PLACE ORDER</button>
                </div>
        </div>

        <!-- side div for price details card -->
        <div class="priceDetails-div">
            <div class="price-heading">Price Details</div>
            <div class="price"></div>
            <div class="discount">
                <div>Discount</div>
                <div class="discount-offered"></div>
            </div>

            <div class="delivery-charges">
                <div>Delivery Charges</div>
                <div class="free">FREE</div>
            </div>
            <hr />

            <div class="total-amount">
                <div>Total Amount</div>
                <div class="amount"></div>
            </div>
            <hr />
            <div class="offer-onAmount"></div>
        </div>
    </div>
    <script src="Cart.js"></script>
</body>

Cart.js

let cart=[];  
// Fetching product data from API 

const fetchData = async() => {
try {
    let { products } = await(await fetch("productData.json")).json();
    cart = products.map((product) => ({...product, qty: 1}));    
    updateCart(cart)
    updatePrice(cart);
} catch (error) {
    console.log(error);
}};

fetchData();

function updateCart(cart) {
    let container = document.querySelector(".product-cart-1");
    let cartHeading = document.querySelector(".cart-heading");

    cartHeading.innerHTML = `My Cart (${cart.length})`;
    container.innerHTML = "";

    for (let i = 0; i < cart.length; i++) {
    let html = `
        <!-- Product cards  -->
        <div class="product-img-inner">
            <div class="product-img"> 
                <img class="img" src="${cart[i].img}" />
                <div class="product-cart1-details">
                 <p class="product-name">${cart[i].name}</p>
                <small class="Product-seller">Seller:${cart[i].seller}
                    <img class="fAssured-true" src="https://static-assets- 
                  web.flixcart.com/www/linchpin/fk-cp-zion/img/fa_62673a.png" />
                </small>
                <!-- Product details -->
                <div class="Product-details">
                    <p class="final-price">${cart[i].finalPrice} ${cart[i].currency}</p>   &nbsp;
                    <p class="original-price">${cart[i].originalPrice} ${cart[i].currency}</p>&nbsp;
                    <p class="discount-percentage">${cart[i].discountPercentage}% OFF</p>&nbsp;
                    <p class="product-offer">${cart[i].offers.count} Offers available</p>
                    <svg width="14" height="14" xmlns="http://www.w3.org/2000/svg" class="_3GN0Y0"><g fill="none"><path d="M-1-1h16v16H-1"></path><path d="M7 0C3.136 0 0 3.136 0 7s3.136 7 7 7 7-3.136 7-7-3.136-7-7-7zm.7 10.5H6.3V6.3h1.4v4.2zm0-5.6H6.3V3.5h1.4v1.4z" fill="#388e3c" class=""></path></g></svg>
                </div>
                </div>

                <!-- Product delivery details -->
                <div class="product-cart1-delivery-details">
                    <p class="product-delivery-date">Delivery by ${cart[i].delivery.estimatedDate} | Free <span class="strike-fee"> ā‚¹${cart[i].delivery.originalDeliveryCharge}</span></p>
                    <small class="product-replacement">${cart[i].delivery.replacementPolicyDuration} Replacement Policy</small>
                </div>
            </div>

    container.innerHTML += html;
    }
}

After fetching up the data from API endpoints, I used HTML elements in JS and passed the fetched data with the help of Template Literals. and used the index in cart array to avoid differentiate between both the products. This has been done to easily update the quantity, price and remove the cart item without facing redundancy issues.

Now comes the Heart of JavaScript -> FUNCTIONS.

tenor (2).gif Yes, This is what JS feels about FUNCTIONS. LOL, šŸ˜‚ that's true.

So, Coming further. I used functions for implementing all the functionalities. Starting up with Incrementing and decrementing the quantity.

function decrementQty(i) {
    if(cart[i].qty === 1) return
    let getItem = document.querySelectorAll("#quantity__input")[i];
    cart[i].qty--;
    getItem.value = cart[i].qty;
    updatePrice(cart)
}

function incrementQty(i) {
    let getItem = document.querySelectorAll("#quantity__input")[i];
    cart[i].qty++;
    getItem.value = cart[i].qty;
    updatePrice(cart)
}

It simply takes the index[i] of the cart and increments or decrements the quantity of the product inside an input element, a reference of which is taken by its id through document.querySelectorAll().

Now Under the price details section, Let's update the price, discount, and offers by updatePrice() function.

function updatePrice(cart){
    let getPriceElement = document.querySelector(".price"); 
    let getDiscountElement = document.querySelector(".discount-offered"); 
    let totalAmountSaveElement = document.querySelector(".offer-onAmount"); 
    let getAmountElement = document.querySelector(".amount"); 
    let totalPrice = cart.reduce((acc,i) => acc + i.qty*i.originalPrice,0)
    let totalItem = cart.reduce((acc,i) => acc + i.qty,0)
    let totalDiscount = cart.reduce((acc,i) => acc + parseInt(i.qty*i.originalPrice) - i.qty*i.finalPrice,0)

    let price = `
    <div>Price (${totalItem} items)</div>
    <div>ā‚¹ ${totalPrice.toLocaleString()}</div>
    `
    getPriceElement.innerHTML = price;
    getDiscountElement.innerHTML = `- ${totalDiscount.toLocaleString()}`;
    getAmountElement.innerHTML = `ā‚¹ ${(totalPrice - totalDiscount).toLocaleString()}`;
    totalAmountSaveElement.innerHTML = `You'll save ${totalDiscount.toLocaleString()} on this order.`
}

Here, I took the updatePrice(cart) function wherein the cart is taken as a parameter. Now, declared the totalPrice, totalItem, totalDiscount and performed a reduce method for calculation of the total items, price, and discount.

Then similarly, by using innerHTML, it returns the HTML content wherein, I have used template literals for displaying the updated Values.

But wait, if we manually give quantity inside the input element, the price and other things don't get updated accordingly. Let's fix that too šŸ¤”

function updateQty(i){
    let getItem = document.querySelectorAll("#quantity__input")[i];
    cart[i].qty = parseInt(getItem.value);
    updatePrice(cart)
}

The code says it all. the function takes the index and updates the value whatever it gets from the user. And finally updates the price according to the quantity the input element has.

Now, comes the deletion part. Let's also remove the product or item from the cart. Again, will be using the function:-

function removeItem(i){
    cart = cart.filter((_, index) => index !== i )
    updateCart(cart)
    updatePrice(cart)
}

removeItem(i) takes an index as a parameter and with the help of the filter method -> creates a new array with all elements that pass the condition (which is -> where index !== i ) implemented by the removeItem().

And finally, it also updates the cart in updateCart() function (where the product cart inside the <div> has been displayed) and also updates the prices accordingly through updatePrice() function.

That's all, we had to do in this -> to complete the task. Here's the working version of the same:- Have a look

ezgif-7-6b43e98659b9.gif

The link to the source code and deployed page is here

I hope you got to learn something from this documentation. Share it with your friends who can benefit from this.

See you guys in the next one. Cheers :)

Did you find this article valuable?

Support TheNovation by becoming a sponsor. Any amount is appreciated!