Velo Tutorial: Adding Multiple Items to the Cart in a Wix Stores Site

Visit the Velo by Wix website to onboard and continue learning.

Note: This tutorial and its steps are based on a Wix Editor site. You can adapt the steps for a Wix Studio site by using the equivalent Wix Studio features.

This article describes how you can use Velo to add multiple items at once to the shopping cart in a Wix Stores site. Throughout this article, we're going to use this site to illustrate the process. You can follow along by opening the site in the Wix Editor. We're going to explain how we set up the sample site and the code we added to make it work.

Overview

Our site allows visitors to create a custom charm bracelet. Visitors choose the material of the bracelet and 5 charms to add to it. When the site visitor finishes the customization process, the bracelet—along with all of the chosen charms—are added to the shopping cart. 

Our site contains a Wix Store with all the different bracelet and charm types.

We also added a Charm Bracelet page which contains:

  • An image of a charm bracelet with five overlayed images for charms that are added to the bracelet. The overlayed images are hidden on load.
  • Three collapsable sections implemented using container boxes. These sections represent the three steps a site visitor is required to complete before purchasing a custom bracelet. Steps 1 and 2 contain a button to move to the next section, and step 3 contains a button to add the items to the cart. Site visitors can also move between sections by clicking on the text elements that serve as the section headers. 
    • The first section contains three buttons for choosing the bracelet material.
    • The second section contains a repeater that shows the available and selected charms.
    • The third section contains a text element that shows which material bracelet was chosen, a repeater that shows which charms were chosen, and another text element that shows the total price.
  • A shopping cart. 

Then we added code to do the following:

  • Set up the page's navigation so site visitors can easily switch between sections.
  • Get the product information for the bracelet and all the charms.
  • Add repeater data and logic for selecting and displaying bracelet charms.
  • Calculate the price of the selected bracelet and charms, and add them to the store's shopping cart.

Step 1: Set Up the Site

To recreate this functionality, you'll need to have Wix Stores added to your site with some products. In our site, the products are the different bracelet and charm types. Once you add Stores to your site, you'll see pages and collections automatically added to your site.

Notes:

  • In this example we don't work with the Collections collection, although it is in our sample site's store. 
  • You may need to save or publish the site and refresh your browser to view the Stores collections in the Database.

This is what some of the data in our site looks like:

Step 2: Set Up the Charm Bracelet Page

Here's everything we added on the Charm Bracelet page:

  • A dataset connected to the Products collection.

  • A shopping cart.

  • Images for the bracelet and charms. The bracelet image changes based on the chosen material. The charmPlace images change based on the selected charms.

     

  • Some text elements for displaying explanatory information.

  • Three buttons styled to look like section headings.

  • Three container boxes for the three steps in the customization process. Elements are grouped in a container boxes so that they can easily be collapsed and expanded together.

    • The first container box contains buttons for choosing the bracelet material, and a button for moving to the next step.

    • The second container box contains a repeater for choosing the bracelet charms, and a button for moving to the next step. Each repeater item consists of three layers:

      • A charm overlay for indicating whether the charm is still available for selection.
      • A charm image that shows the actual charm.
      • A charm border for indicating whether the charm is selected.
    • The third container box contains elements for reviewing the customized bracelet and adding the items to the shopping cart.

      • A text element to show the material of the selected bracelet.
      • A repeater to show the selected charms.
      • A text element to show the price of the selected bracelet and charms.
      • A button to add all the selected items to the cart.

Step 3: Create an Import and Global Variables

All of the code in this site is added to the Charm Bracelet page. 

The code begins with an import statement and some variable declarations.

Copy
1
import wixData from 'wix-data';
2
3
const MAX_NUMBER_OF_CHARMS = 5;
4
const selectedCharms = [];
5
let braceletsMap = {};
6
let selectedBracelet;

Line 1: Import the wix-data module, which is used to query the site's collections.
Line 3: Create a constant that determines the maximum number of charms that can be added to the bracelet.
Line 4: Create an array that will contain the charms that are selected by the site visitor.
Line 5: Create an object that will contain the product information for the various types of bracelets.
Line 6: Create a variable to store the type of bracelet selected.

Step 4: Create the onReady Function

When the page loads, get the product information for the various types of bracelets and store it in a convenient way to use later.

Note: Throughout this example we use the async/await JavaScript functionality.

Copy
1
$w.onReady(async () => {
2
const braceletNames = ['Silver Bracelet', 'Rose Gold Bracelet', 'Gold Bracelet'];
3
let newQuery = await wixData.query("Stores/Products")
4
.hasSome("name", braceletNames).find();
5
const allBracelets = newQuery.items;
6
allBracelets.forEach(product => {
7
const keyName = product.name.split(' ')[0].toLowerCase();
8
braceletsMap[keyName] = product;
9
});
10
});

Line 1: Declare the onReady() event handler.
Line 2: Create an array of all the available bracelet types.
Line 3-4: Query the Products collection to find the products that match the bracelet names from the list created in line 2.
Line 5: Get the items returned in the query results.
Line 6-8: For each item returned by the query, create a key in the braceletsMap object corresponding to the bracelet type (e.g., the key for 'Silver Bracelet' is set as silver). Then set the value for that key to the product information retrieved for that type of bracelet.

Step 5: Create onClick Functions for Each Header

Each step in the customization process has a header. The header is actually a button that site visitors can click to expand the relevant section and collapse all other sections.

Copy
1
export function selectBraceletText_click(event, $w) {
2
$w('#bracelectSelectionStrip').expand();
3
$w('#charmsSelectionStrip').collapse();
4
$w('#addToCartStrip').collapse();
5
};
6
7
export function chooseCharmsText_click(event, $w) {
8
$w('#bracelectSelectionStrip').collapse();
9
$w('#charmsSelectionStrip').expand();
10
$w('#addToCartStrip').collapse();
11
};
12
13
export function reviewBraceletText_click(event, $w) {
14
$w('#bracelectSelectionStrip').collapse();
15
$w('#charmsSelectionStrip').collapse();
16
$w('#addToCartStrip').expand();
17
};

Lines 1-5, 7-11, 13-17: When a header button is clicked, expand the corresponding section and collapse all others.

Step 6: Create onClick Functions for Each Material Button

In step 1 of the customization process, site visitors choose the material of the charm bracelet using one of three buttons. The buttons are wired to similar onClick event handlers.

Copy
1
export function gold_click(event, $w) {
2
selectBracelet(braceletsMap.gold);
3
};
4
5
export function silver_click(event, $w) {
6
selectBracelet(braceletsMap.silver);
7
};
8
9
export function rosegold_click(event, $w) {
10
selectBracelet(braceletsMap.rose);
11
};

Lines 1-3, 5-7, 9-11: The button event handlers call the selectBracelet() function, passing the product information corresponding to the chosen material. The selectBracelet() function performs all the necessary changes to the page's elements when the chosen material of the bracelet changes and is described in detail in step 7 of this article.

Step 7: Create the selectBracelet Function

The selectBracelet() function receives the information from the Products collection corresponding to the chosen bracelet material.

Copy
1
function selectBracelet(bracelet) {
2
selectedBracelet = bracelet;
3
$w('#bracelet').src = bracelet.mainMedia;
4
$w('#nextButton').enable();
5
$w('#chooseCharmsText').enable();
6
$w('#selectedBracelet').text = bracelet.name + " + these charms:";
7
$w('#selectedBracelet').show();
8
};

Line 2: Set the selectedBracelet global variable to the product information of the chosen bracelet.
Line 3: Set the bracelet image to the main image from the chosen bracelet's product information.
Line 4: Enable the button used to move to the next step of the customization process. See step 8 of this article for a description of the code that runs when this button is clicked.
Line 5: Enable the heading used to move to the next step of the customization process. See step 5 of this article for a description of the code that runs when this button is clicked.
Line 6: Set the review text in step 3 of the customization process to reflect the selected bracelet type.
Line 7: Show the review text in step 3 of the customization process.

Step 8: Create the nextButton_click Function

The nextButton_click() function is wired to the next button in step 1 of the customization process. The button is used to move to step 2.

Copy
1
export function nextButton_click(event, $w) {
2
$w('#bracelectSelectionStrip').collapse();
3
$w('#charmsSelectionStrip').expand();
4
$w('#chooseCharmsText').enable();
5
}

Line 2: Collapse the first section.
Line 3: Expand the second section.
Line 4: Enable the header button of the second section.

Step 9: Create the charmsRepeater_itemReady Function

The charmsRepeater_itemReady() function is wired to the repeater used to select charms in step 2 of the customization process. The function is called for each repeater item as it is created. It sets what happens when a specific charm is clicked.

Copy
1
export function charmsRepeater_itemReady($w, itemData, index) {
2
$w('#charmImage').onClick(() => {
3
if ($w('#charmBorder').hidden) {
4
selectedCharms.push(itemData);
5
$w('#charmBorder').show();
6
showCharmOnBracelet(itemData.mainMedia);
7
$w('#selectedCharmsRepeater').data = selectedCharms;
8
if (selectedCharms.length === MAX_NUMBER_OF_CHARMS) {
9
disableCharmsSelection();
10
}
11
} else {
12
if (selectedCharms.length === MAX_NUMBER_OF_CHARMS) {
13
enableCharmsSelection();
14
}
15
const indexOfCharm = selectedCharms.findIndex(item => item._id === itemData._id);
16
selectedCharms.splice(indexOfCharm, 1);
17
$w('#selectedCharmsRepeater').data = selectedCharms;
18
hideCharmFromBracelet(itemData.mainMedia);
19
$w('#charmBorder').hide();
20
}
21
});
22
};

Line 2: Create an onClick event handler on the charm image.
Line 3: If the item's border is hidden, meaning the charm is not currently selected:
Line 4: Add the clicked charm to the list of selected charms.
Line 5: Show the border to indicate that the charm is now selected.
Line 6: Call the showCharmOnBracelet() function with the selected charms image. The showCharmOnBracelet() function adds the specified charm image to the next open spot on the bracelet image, as described in step 10 of this article.
Line 7: Reset the repeater in step 3 of the customization process to reflect the newly selected charm.
Lines 8-10: If the selection means the maximum number of charms has been reached, disable further charm selection by calling the disableCharmsSelection() function described in step 11 of this article.
Line 11: If the item's border is shown, meaning the charm is currently selected:
Lines 12-14: If the deselection means the maximum number of charms is no longer selected, enable further charm selection by calling the enableCharmsSelection() function described in step 11 of this article.
Lines 15-16: Find the index of the charm that is being deselected and remove it from the list of selected charms.
Line 17: Reset the repeater in step 3 of the customization process to reflect the newly deselected charm.
Line 18: Call the hideCharmFromBracelet() function with the selected charms image. The hideCharmFromBracelet() function removes the specified charm image from the bracelet image, as described in step 10 of this article.
Line 19: Hide the border to indicate that the charm is no longer selected.

Step 10: Create the showCharmOnBracelet and hideCharmFromBracelet Functions

The showCharmOnBracelet() and hideCharmFromBracelet() functions are used to add or remove charms from the bracelet image when they are selected in step 2 of the customization process.

Copy
1
function showCharmOnBracelet(charmImage) {
2
for (let i = 1; i <= 5; i++) {
3
if ($w(`#charmPlace${i}`).hidden) {
4
$w(`#charmPlace${i}`).src = charmImage;
5
$w(`#charmPlace${i}`).show();
6
break;
7
}
8
}
9
};
10
11
function hideCharmFromBracelet(charmImage) {
12
for (let i = 1; i <= 5; i++) {
13
if ($w(`#charmPlace${i}`).src === charmImage) {
14
$w(`#charmPlace${i}`).src = 'http://';
15
$w(`#charmPlace${i}`).hide();
16
break;
17
}
18
}
19
};

Lines 2-8: Find the first charm place with a hidden charm image, set its image to be the passed in image, and then show the charm image.

Lines 12-18: Find the charm place that matches the passed in image, set its image source to a blank image, and then hide the charm image.

Step 11: Create the disableCharmsSelection and enableCharmsSelection Functions

The disableCharmsSelection() and enableCharmsSelection() functions are used to disable or enable the selection of charms in step 2 of the customization process.

Copy
1
function disableCharmsSelection() {
2
$w('#charmsRepeater').forEachItem(($w, itemData) => {
3
if (!isCharmSelected(itemData)) {
4
$w('#charmOverlay').show();
5
}
6
});
7
};
8
9
function enableCharmsSelection() {
10
$w('#charmsRepeater').forEachItem($w => {
11
$w('#charmOverlay').hide();
12
});
13
};

Lines 2-6: For each item in the charms repeater, if the charm isn't selected, show the overlay, which stops the item from being selected. To determine if the charm is selected, the isCharmSelected() function is called. The isCharmSelected() function is described in step 12 of this article.

Lines 9-12: For each item in the charms repeater, hide the overlay, which allows the charms to be selected.

Step 12: Create the isCharmSelected Function

The isCharmSelected() function checks to see if a specific charm is selected.

Copy
1
function isCharmSelected(charmItem) {
2
return selectedCharms.findIndex(item => item._id === charmItem._id) > -1;
3
};

Line 2: Use the JavaScript findIndex() function to check if the specified charm exists in the list of selected charms.

Step 13: Create the selectedCharmsRepeater_itemReady Function

The selectedCharmsRepeater_itemReady() function is wired to the repeater used to display the selected charms in step 3 of the customization process. The function is called for each repeater item as it is created.

Copy
1
export function selectedCharmsRepeater_itemReady($w, itemData, index) {
2
$w('#selectedCharmImage').src = itemData.mainMedia;
3
};

Line 2: Set the item's image to the specified image from the repeater's data.

Step 14: Create the finishButton_click Function

The finishButton_click() function is wired to the finish button in step 2 of the customization process. The button is used to move to step 3 of the process.

Copy
1
export function finishButton_click(event, $w) {
2
$w('#bracelectSelectionStrip').collapse();
3
$w('#charmsSelectionStrip').collapse();
4
calcAndShowPrice();
5
$w('#addToCartStrip').expand();
6
$w('#reviewBraceletText').enable();
7
$w('#addToCartButton').enable();
8
};

Line 2-3: Collapse sections one and two.
Line 4: Calculate the price of the bracelet and charms to be displayed in section three using the calcAndShowPrice() function. The calcAndShowPrice() function is described in step 15 of this article.
Line 5: Expand the third section.
Line 6: Enable the heading used to move to step 3 of the customization process. See step 5 of this article for a description of the code that runs when this button is clicked.
Line 7: Enable the button that adds the bracelet and selected charms to the store's shopping cart. See step 16 of this article for a description of the code that runs when this button is clicked.

Step 15: Create the calcAndShowPrice Function

The calcAndShowPrice() function calculates the price of the selected bracelet and charms. It then shows the price in the third section.

Copy
1
function calcAndShowPrice() {
2
let price = selectedBracelet.price;
3
selectedCharms.forEach(charm => {
4
price += charm.price;
5
});
6
$w('#price').text = price.toString();
7
};

Line 2: Get the price of the selected bracelet.
Lines 3-5: For each selected charm, add its price to the total price.
Line 6: Show the calculated price in the third section.

Step 16: Create the addToCartButton_click Function

The addToCartButton_click() function is wired to the add to cart button in step 3 of the customization process. The button is used to add the selected bracelet and charms to the store's shopping cart.

Copy
1
export async function addToCartButton_click(event, $w) {
2
let itemsToAdd = [{ productID: selectedBracelet._id, quantity: 1, options: {} }];
3
selectedCharms.forEach(function (charm) {
4
itemsToAdd.push({ productID: charm._id, quantity: 1, options: {} });
5
});
6
let res = await $w('#shoppingCartIcon').addProductsToCart(itemsToAdd);
7
};

Lines 2-4: Define the bracelet and charms to be added to the shopping cart.
Line 6: Add the bracelet and selected charms all at once to the store's shopping cart.

Next Steps

Was this helpful?
Yes
No