In the previous experiment, I created a <buy-button>
web component. In this experiment, I add an “add to cart” button as well.
API
The API will be similar to the <buy-button>
:
<!-- import js -->
<script src="https://domain.tld/cart.js"></script>
<!-- define a button -->
<add-button sku="t-shirt">Add to Cart</add-button>
Cart Storage
A cart can be stored server side or client side. This example will use the client side approach and persis the data in the browser’s localStorage
.
In fact, I built a Svelte store for localStorage
called svelte-local-storage-store
, which will work perfectly here.
The idea is to have a dictionary with sku
as the key and quantity
as the value, ie {sku: quantity, ...}
. We’ll also define accessor functions, like add()
, clear()
etc.. And to count the total quantity in the cart, we can use a derived
store.
import { derived } from 'svelte/store'
import { writable } from 'svelte-local-storage-store'
// a store backed by local storage
export const cart = writable('cart', {})
// the count of items in the cart is derived from the cart store
export const count = derived(cart, $cart => {
// use Array.reduce() to sum the quantity.
return Object
.keys($cart)
.reduce((acc, key) => acc + $cart[key], 0)
})
// add an item to the cart
export function add(sku) {
// update the store
cart.update($cart => {
// check if the item already exists in the cart
if ($cart[sku]) {
// there's already one in the cart, so increment quantity
$cart[sku]++
} else {
// it doesn't exist, so add it to the store with a quantity of 1
$cart[sku] = 1
}
return $cart
})
}
// clear the cart by setting it to an empty dictionary
export function clear() {
cart.set({})
}
Button definition
The <add-button>
is very similar the <buy-button>
except it uses the cart:
<svelte:options tag="add-button"/>
<script>
import {cart, add} from './cart'
export let sku
if (!sku) console.error('<add-button> sku must be set')
function submit() {
add(sku)
}
</script>
<form on:submit|preventDefault={submit}>
<button part="button">
<slot/>
</button>
</form>