Skip to main content
Version: next

Shopify Cart

The cart is an example of a global service which multiple components in a theme might need to access. In SALVO-TS, this is represented via the Cart class and it's cart instance (defined in src/theme/Cart.ts).

You can access the cart instance by importing it.

ts
import { cart } from '@/theme/Cart';
 
console.log(cart.items[0]);
// { id: 12345678, title: "...", price: 12.23, ... }
ts
import { cart } from '@/theme/Cart';
 
console.log(cart.items[0]);
// { id: 12345678, title: "...", price: 12.23, ... }

Quick reference

The following actions are available on the default cart instance:

Access items
Get all items
ts
for (let item of cart.items) {
console.log('got item', item);
}
ts
for (let item of cart.items) {
console.log('got item', item);
}
Get item by line
ts
const item = cart.items[4];
ts
const item = cart.items[4];
Get item by SKU
ts
const bracelets = cart.queryItems({ sku: 'BRACELET01' });
ts
const bracelets = cart.queryItems({ sku: 'BRACELET01' });
Get item by product or variant
ts
const selectionPacks = cart.queryItems({ productId: 1243456789 });
const chocolateFlavours = cart.queryItems({ variantId: 5688912344 });
ts
const selectionPacks = cart.queryItems({ productId: 1243456789 });
const chocolateFlavours = cart.queryItems({ variantId: 5688912344 });
Get item by properties
ts
// Property exists
const giftItems = cart.queryItems({ hasProperties: ['_gift_message'] });
// Property has specific value
const fitmentProducts = cart.queryItems({ properties: { _install_method: 'fitment' } });
ts
// Property exists
const giftItems = cart.queryItems({ hasProperties: ['_gift_message'] });
// Property has specific value
const fitmentProducts = cart.queryItems({ properties: { _install_method: 'fitment' } });
Get by multiple conditions
ts
const braceletsWithGiftMessage = cart.queryItems({
sku: 'BRACELET01',
hasProperties: ['_gift_message']
});
ts
const braceletsWithGiftMessage = cart.queryItems({
sku: 'BRACELET01',
hasProperties: ['_gift_message']
});
Update items
Add item by variant ID
ts
// Simple
await cart.addItem({ id: 124567890 });
 
// With quantity and attributes
await cart.addItem({
id: 124567890,
quantity: 4,
properties: {
_gift_message: 'Enjoy!',
}
});
ts
// Simple
await cart.addItem({ id: 124567890 });
 
// With quantity and attributes
await cart.addItem({
id: 124567890,
quantity: 4,
properties: {
_gift_message: 'Enjoy!',
}
});
Add multiple items
ts
await cart.addItems([
{ id: 1234567890 },
{ id: 1234567890, quantity: 2 },
{
id: 1234567890,
quantity: 4,
properties: {
_gift_message: 'Enjoy!',
}
},
]);
ts
await cart.addItems([
{ id: 1234567890 },
{ id: 1234567890, quantity: 2 },
{
id: 1234567890,
quantity: 4,
properties: {
_gift_message: 'Enjoy!',
}
},
]);
Update item quantity and attributes
ts
await item.changeQuantity(2);
await item.changeProperties({
_gift_message: 'Enjoy!',
});
// Combine both:
await item.change(2, {
_gift_message: 'Enjoy!',
});
ts
await item.changeQuantity(2);
await item.changeProperties({
_gift_message: 'Enjoy!',
});
// Combine both:
await item.change(2, {
_gift_message: 'Enjoy!',
});
Remove item
ts
await item.remove();
ts
await item.remove();
Cart attributes
Get cart attributes
ts
console.log('packaging preference', cart.attributes._packaging_preference);
for (const [key, value] of Object.entries(cart.attributes)) {
console.log(`attribute: ${key} = ${value}`);
}
ts
console.log('packaging preference', cart.attributes._packaging_preference);
for (const [key, value] of Object.entries(cart.attributes)) {
console.log(`attribute: ${key} = ${value}`);
}
Update cart attributes
ts
await cart.updateAttributes({
_vat_number: '12345678',
});
ts
await cart.updateAttributes({
_vat_number: '12345678',
});
Cart note
Get cart note
ts
console.log('cart note', cart.note);
ts
console.log('cart note', cart.note);
Update cart note
ts
await cart.updateNote(`Engraving option: A`);
ts
await cart.updateNote(`Engraving option: A`);

Extending the cart interface

You can extend the cart, for example to add new utility functions, by editing the src/theme/Cart.ts file.

src/theme/Cart.ts
ts
import { BaseCart, CartItem, ShopifyCartItemInput } from '@eastsideco/salvo-ts';
 
class Cart extends BaseCart {
/**
* Adds an item to the cart and marks it as a gift.
* The gift message will be attached as the _gift_message attribute.
*/
async addGiftItem(variantId: number, giftMessage: string, opts: ShopifyCartItemInput) {
return await this.addItems([
{
...opts,
id: variantId,
properties: {
...opts.properties,
_gift_message: giftMessage,
}
},
]);
}
}
export const cart = new Cart();
src/theme/Cart.ts
ts
import { BaseCart, CartItem, ShopifyCartItemInput } from '@eastsideco/salvo-ts';
 
class Cart extends BaseCart {
/**
* Adds an item to the cart and marks it as a gift.
* The gift message will be attached as the _gift_message attribute.
*/
async addGiftItem(variantId: number, giftMessage: string, opts: ShopifyCartItemInput) {
return await this.addItems([
{
...opts,
id: variantId,
properties: {
...opts.properties,
_gift_message: giftMessage,
}
},
]);
}
}
export const cart = new Cart();

The methods you add to Cart will be available globally on the cart object. You can also add your own custom state and events here, for instance to keep track of the open-state of a side-cart drawer or popover.

Extending queryItems

You can extend the queryItems method by calling addQueryType, and augmenting the CartItemQuery interface:

src/theme/Cart.ts
ts
import { BaseCart, CartItem, CartItemQuery } from '@eastsideco/salvo-ts';
 
declare module '@eastsideco/salvo-ts' {
interface CartItemQuery {
/** Match items with a variant SKU starting with a substring */
skuPrefix: string;
}
}
 
export default class Cart extends BaseCart {
constructor() {
super();
 
// Add a new query option which will match items based on a SKU prefix
this.addQueryType('skuPrefix', (items: CartItem[], prefix: string) => {
return items.filter((item: CartItem) => item.sku.endsWith(prefix));
});
}
}
export const cart = new Cart();
src/theme/Cart.ts
ts
import { BaseCart, CartItem, CartItemQuery } from '@eastsideco/salvo-ts';
 
declare module '@eastsideco/salvo-ts' {
interface CartItemQuery {
/** Match items with a variant SKU starting with a substring */
skuPrefix: string;
}
}
 
export default class Cart extends BaseCart {
constructor() {
super();
 
// Add a new query option which will match items based on a SKU prefix
this.addQueryType('skuPrefix', (items: CartItem[], prefix: string) => {
return items.filter((item: CartItem) => item.sku.endsWith(prefix));
});
}
}
export const cart = new Cart();

Handling external updates

In most cases, SALVO-TS will automatically detect when third parties (i.e. apps) modify the cart and will automatically reload the cart state.

If this fails for some reason, you can manually notify the cart by calling notifyCartUpdatedExternally().

src/components/WishlistExample.ts
ts
@Component
export class WishlistExample extends ThemeComponent {
async addWishlistItemToCart() {
// Trigger some cart change in a third party app which can't be picked up automatically
const wishlistItem = window.thirdPartyWishlistApp.items[0];
await window.thirdPartyWishlistApp.moveItemToCart(wishlistItem);
 
// Manually notify the theme to pick up the cart changes
await cart.notifyCartUpdatedExternally();
}
}
src/components/WishlistExample.ts
ts
@Component
export class WishlistExample extends ThemeComponent {
async addWishlistItemToCart() {
// Trigger some cart change in a third party app which can't be picked up automatically
const wishlistItem = window.thirdPartyWishlistApp.items[0];
await window.thirdPartyWishlistApp.moveItemToCart(wishlistItem);
 
// Manually notify the theme to pick up the cart changes
await cart.notifyCartUpdatedExternally();
}
}