DEV Community

Cover image for Create Shopping Cart using Alpinejs
Andrew Saeed
Andrew Saeed

Posted on

Create Shopping Cart using Alpinejs

In this blog post, we'll delve into the process of creating a shopping cart using Alpine.js. We'll explore how to structure components, manage state with Alpine's store, and implement essential features such as fetching new products, adding and removing items, calculating total price, and handling UI interactions.

Content

Alpine.js stands out as a lightweight yet powerful tool, perfect for developers who want to add interactivity to their web pages without the overhead of a full-fledged framework, also it is great for SEO.

Allow me to show you!

Create the main Component

Let's define an Alpine.js component called shoppingCartProductsList, it will manage the state and behavior of a shopping cart product list, including loading products from an API, handling pagination, and toggling the visibility of the shopping cart:

Component Initialization

Alpine.data('shoppingCartProductsList', (): ShoppingCartProductsList => ({}))
Enter fullscreen mode Exit fullscreen mode

Alpine.data() defines a new Alpine.js component named shoppingCartProductsList. It returns an object that contains the state and methods for this component.

State Variables

toggleCart: false,
loading: false,
products: [],
limit: 10,
page: 1,
Enter fullscreen mode Exit fullscreen mode
  • toggleCart: Controls the visibility of the shopping cart (initially hidden).
  • loading: Indicates whether the component is currently loading data from the API.
  • products: An array to store the list of products fetched from the API.
  • limit: Specifies the number of products to fetch per page.
  • page: Tracks the current page number for pagination.

Initialization (init method)

async init() {
    this.loading = true
    const res = await axios.get<ProductsGetRes>('https://dummyjson.com/products?limit=10&skip=0')
    this.products = res.data.products
    this.loading = false
},
Enter fullscreen mode Exit fullscreen mode

It is an asynchronous method that runs when the component is initialized. It fetches the first batch of products from the API using Axios and stores them in the products array. The loading state is set to true while the data is being fetched, and then reset to false once the data is loaded.

Pagination (paginate method)

async paginate() {
    if (this.loading) return
    this.loading = true

    this.page += 1
    const skip = (this.page - 1) * this.limit;
    const res = await axios.get<ProductsGetRes>(`https://dummyjson.com/products?limit=${this.limit}&skip=${skip}`)
    this.products = [...this.products, ...res.data.products]

    this.loading = false
},
Enter fullscreen mode Exit fullscreen mode

Another asynchronous method for loading more products as the user navigates through pages by clicking the load more button. It first checks if the component is already loading to prevent multiple requests.
The page number is incremented, and the skip value is calculated to determine which products to fetch.
The newly fetched products are appended to the existing products array.

Toggle Cart (toggleCartHandler method)

toggleCartHandler() {
    this.toggleCart = !this.toggleCart
    if (this.toggleCart) {
        document.body.style.overflowY = 'hidden';
        (Alpine.store('shoppingCartTheCart') as ShoppingCartTheCart).currentView = 'cart';
    } else {
        document.body.style.overflowY = 'scroll'
    }
}
Enter fullscreen mode Exit fullscreen mode

A method for toggling the visibility of the shopping cart.
When the cart is toggled on, the page's vertical scroll is disabled by setting overflowY to hidden.
It also updates the currentView property of another Alpine.js store shoppingCartTheCart to show the cart view. When toggled off, the vertical scroll is restored.

Create the Store

Let's define a store that will manage the state and actions related to the shopping cart, such as adding and removing products, calculating the total price, and handling UI interactions.

Store Initialization

const shoppingCartTheCart: ShoppingCartTheCart = {}
Alpine.store('shoppingCartTheCart', shoppingCartTheCart)
Enter fullscreen mode Exit fullscreen mode

shoppingCartTheCart is a constant with the type ShoppingCartTheCart. The object holds the properties and methods necessary to manage the shopping cart. I will use it to register shoppingCartTheCart as a global store in Alpine.js.
This makes the shopping cart's state and methods accessible from any Alpine.js component within the application.

State Variables

totalPrice: 0,
totalProducts: 0,
products: [],
cartBtnToggler: document.querySelector('#cartBtnToggler')!,
currentView: 'cart',
Enter fullscreen mode Exit fullscreen mode
  • totalPrice: Tracks the total price of all products in the cart.
  • totalProducts: Tracks the total number of products in the cart.
  • products: An array that stores the products added to the cart.
  • cartBtnToggler: A reference to the HTML element with the ID -
  • cartBtnToggler, used for handling UI interactions (e.g., animations).
  • currentView: A string that indicates the current view of the cart, defaulted to cart.

Initialization (init method)

init() {
    this.cartBtnToggler.addEventListener('animationend', () => {
        this.cartBtnToggler.classList.remove('animate__rubberBand')
    })
},
Enter fullscreen mode Exit fullscreen mode

This method runs when the shopping cart store is initialized.
It adds an event listener to cartBtnToggler that listens for the end of an animation.
Once the animation ends, the method removes the animate__rubberBand class from the button, ensuring that the animation can be re-triggered later.

Adding a Product (addProduct method)

addProduct(newProduct: Product) {
    this.totalPrice += newProduct.price
    this.totalProducts += 1
    const productIndex = this.products.findIndex(product => product.id === newProduct.id)
    if (productIndex > -1) {
        this.products[productIndex].amount += 1
    } else {
        this.products.push({ ...newProduct, amount: 1 })
    }
    this.cartBtnToggler.classList.add('animate__rubberBand')
},
Enter fullscreen mode Exit fullscreen mode

This method adds a new product to the shopping cart. It first increments the totalPrice and totalProducts to reflect the new addition.
The method checks if the product is already in the cart using findIndex:

  • If the product exists (i.e., productIndex > -1), it increments the amount of that product.
  • If the product is new, it is added to the products array with an initial amount of 1.
  • Finally, the method triggers the animate__rubberBand animation on the cart button to provide visual feedback.

Removing a Product (removeProduct method)

removeProduct(productToRemove: CartProduct) {
    this.totalPrice = Math.round((this.totalPrice - productToRemove.price) * 100) / 100;
    this.totalProducts -= 1
    const productToRemoveIndex = this.products.findIndex(product => product.id === productToRemove.id)
    if (productToRemove.amount === 1) {
        this.products.splice(productToRemoveIndex, 1)
    } else {
        this.products[productToRemoveIndex].amount -= 1
    }
}
Enter fullscreen mode Exit fullscreen mode

This method removes a product from the shopping cart.
It first decrements the totalPrice by the price of the product being removed, rounding it to two decimal places. The totalProducts count is also decremented. The method finds the product in the products array using findIndex:

  • If the product's amount is 1, it is completely removed from the cart using splice.
  • If the product's amount is greater than 1, the amount is simply decremented by 1.

Summary and the source code

I like to use Alpine.js to build cool websites. It is very easy to create components and stores using Alpine.js, which helps a lot in quickly adding interactivity to any web page without hurting SEO.

🙏 Your feedback is much appreciated

Full Code

Working Example

ko-fi

Top comments (0)