I am currently building this e-commerce store and I want to have a modal as my cart using skeleton UI. Everything works except that the cart doesn't update immediately, but if I close the modal and open it again everything works fine. I also use the local storage store by skeleton UI. Here is my cart.svelte:
<script lang="ts">
import CartProduct from './cartProduct.svelte';
import { cartItems } from './cart';
import { get, writable, type Writable } from 'svelte/store';
import { getProductData } from '../routes/products';
let subtotal = writable(0);
const getSubtotal = () => {
let total = 0;
$cartItems.forEach((item) => {
if (item && item.id) {
const productData = getProductData(item.id);
if (productData) {
total += productData.price * item.quantity;
}
}
});
subtotal.set(total);
};
$: getSubtotal();
</script>
<div class="bg-surface-100-800-token card p-8 w-[90%] max-h-[70dvh] relative">
<h1 class="h1 font-black mb-4">Your Cart:</h1>
<div class="overflow-auto max-h-[40dvh]">
{#each $cartItems as item}
<CartProduct itemId={item.id} />
{/each}
</div>
<p>Subtotal: {$subtotal}</p>
<button
class="btn variant-ghost-primary mt-4 h3 font-bold"
on:click={() => console.log('Checkout')}>Check out</button
>
</div>
Here is my cart.ts:
import { get, type Writable } from 'svelte/store';
import { localStorageStore } from '@skeletonlabs/skeleton';
export const cartItems: Writable<CartItem[]> = localStorageStore<CartItem[]>('cartItems', []);
export const addToCart = (id: string) => {
let items = get(cartItems);
let itemPosition = items.findIndex((item) => {
return item.id === id;
});
if (itemPosition === -1) {
cartItems.update(() => {
return [...items, { id: id, quantity: 1 }];
});
} else {
return items;
}
};
export const removeFromCart = (id: string) => {
let items = get(cartItems);
let itemPosition = items.findIndex((item) => item.id === id);
if (itemPosition !== -1) {
cartItems.update((cartItems) => {
return cartItems.filter((item) => item.id !== id);
});
}
};
The state of the cart should be updated in realtime in my modal
The reactive statement
$: getSubtotal();
by itself has very limited use because it has no right-hand side variable to be reactive upon. This causes the statement to run only once - when the component (i.e. your modal) is instantied.
Try modifying the signature of your function to
const getSubtotal = (items) => {
let total = 0;
items.forEach((item) => {
if (item && item.id) {
const productData = getProductData(item.id);
if (productData) {
total += productData.price * item.quantity;
}
}
});
subtotal.set(total);
};
and your reactive statement to
$: getSubtotal($cartItems);
which in effect is saying "run this function again everytime $cartItems
changes", and then uses the updated $cartItems
value as a parameter in your computation function.