> Portal Navigation:
>
> - Append `.md` to any URL under `https://dev.wix.com/docs/` to get its markdown version.
> - Pages are either content pages (article or reference text) or menu pages (a list of links to child pages).
> - To get a menu page, truncate any URL to a parent path and append `.md` (e.g. `https://dev.wix.com/docs/sdk.md`, `https://dev.wix.com/docs/sdk/core-modules.md`).
> - Top-level index of all portals: https://dev.wix.com/docs/llms.txt
> - Full concatenated docs: https://dev.wix.com/docs/llms-full.txt
## Resource: Adding Multiple Items to the Cart in a Wix Stores Site
## Article: Adding Multiple Items to the Cart in a Wix Stores Site
## Article Link: https://dev.wix.com/docs/develop-websites/articles/code-tutorials/wix-e-commerce-stores/adding-multiple-items-to-the-cart-in-a-wix-stores-site.md
## Article Content:
# Velo Tutorial: Adding Multiple Items to the Cart in a Wix Stores Site
>**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](https://dev.wix.com/docs/develop-websites/articles/coding-with-velo/overview/about-coding-with-wix-studio.md).
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](https://www.wix.com/code-examples/bulk-add-to-cart-vw) to illustrate the process. You can follow along by opening the site [in the Wix Editor](https://editor.wix.com/html/editor/web/renderer/new?siteId=11e2a942-7c54-4bbb-9ffb-cce15e010fb1&metaSiteId=635e3b99-e23b-428e-8947-0fd14be46ddc&autoDevMode=true). 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 overlaid images for charms that are added to the bracelet. The overlaid images are hidden on load.
* Three collapsible 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.
```javascript
import wixData from 'wix-data';
const MAX_NUMBER_OF_CHARMS = 5;
const selectedCharms = [];
let braceletsMap = {};
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](https://codeburst.io/javascript-es-2017-learn-async-await-by-example-48acc58bad65) JavaScript functionality.
```javascript
$w.onReady(async () => {
const braceletNames = ['Silver Bracelet', 'Rose Gold Bracelet', 'Gold Bracelet'];
let newQuery = await wixData.query("Stores/Products")
.hasSome("name", braceletNames).find();
const allBracelets = newQuery.items;
allBracelets.forEach(product => {
const keyName = product.name.split(' ')[0].toLowerCase();
braceletsMap[keyName] = product;
});
});
```
**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.
```javascript
export function selectBraceletText_click(event, $w) {
$w('#braceletSelectionStrip').expand();
$w('#charmsSelectionStrip').collapse();
$w('#addToCartStrip').collapse();
};
export function chooseCharmsText_click(event, $w) {
$w('#braceletSelectionStrip').collapse();
$w('#charmsSelectionStrip').expand();
$w('#addToCartStrip').collapse();
};
export function reviewBraceletText_click(event, $w) {
$w('#braceletSelectionStrip').collapse();
$w('#charmsSelectionStrip').collapse();
$w('#addToCartStrip').expand();
};
```
**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.
```javascript
export function gold_click(event, $w) {
selectBracelet(braceletsMap.gold);
};
export function silver_click(event, $w) {
selectBracelet(braceletsMap.silver);
};
export function rosegold_click(event, $w) {
selectBracelet(braceletsMap.rose);
};
```
**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.
```javascript
function selectBracelet(bracelet) {
selectedBracelet = bracelet;
$w('#bracelet').src = bracelet.mainMedia;
$w('#nextButton').enable();
$w('#chooseCharmsText').enable();
$w('#selectedBracelet').text = bracelet.name + " + these charms:";
$w('#selectedBracelet').show();
};
```
**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.
```javascript
export function nextButton_click(event, $w) {
$w('#braceletSelectionStrip').collapse();
$w('#charmsSelectionStrip').expand();
$w('#chooseCharmsText').enable();
}
```
**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.
```javascript
export function charmsRepeater_itemReady($w, itemData, index) {
$w('#charmImage').onClick(() => {
if ($w('#charmBorder').hidden) {
selectedCharms.push(itemData);
$w('#charmBorder').show();
showCharmOnBracelet(itemData.mainMedia);
$w('#selectedCharmsRepeater').data = selectedCharms;
if (selectedCharms.length === MAX_NUMBER_OF_CHARMS) {
disableCharmsSelection();
}
} else {
if (selectedCharms.length === MAX_NUMBER_OF_CHARMS) {
enableCharmsSelection();
}
const indexOfCharm = selectedCharms.findIndex(item => item._id === itemData._id);
selectedCharms.splice(indexOfCharm, 1);
$w('#selectedCharmsRepeater').data = selectedCharms;
hideCharmFromBracelet(itemData.mainMedia);
$w('#charmBorder').hide();
}
});
};
```
**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.
```javascript
function showCharmOnBracelet(charmImage) {
for (let i = 1; i <= 5; i++) {
if ($w(`#charmPlace${i}`).hidden) {
$w(`#charmPlace${i}`).src = charmImage;
$w(`#charmPlace${i}`).show();
break;
}
}
};
function hideCharmFromBracelet(charmImage) {
for (let i = 1; i <= 5; i++) {
if ($w(`#charmPlace${i}`).src === charmImage) {
$w(`#charmPlace${i}`).src = 'http://';
$w(`#charmPlace${i}`).hide();
break;
}
}
};
```
**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.
```javascript
function disableCharmsSelection() {
$w('#charmsRepeater').forEachItem(($w, itemData) => {
if (!isCharmSelected(itemData)) {
$w('#charmOverlay').show();
}
});
};
function enableCharmsSelection() {
$w('#charmsRepeater').forEachItem($w => {
$w('#charmOverlay').hide();
});
};
```
**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.
```javascript
function isCharmSelected(charmItem) {
return selectedCharms.findIndex(item => item._id === charmItem._id) > -1;
};
```
**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.
```javascript
export function selectedCharmsRepeater_itemReady($w, itemData, index) {
$w('#selectedCharmImage').src = itemData.mainMedia;
};
```
**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.
```javascript
export function finishButton_click(event, $w) {
$w('#braceletSelectionStrip').collapse();
$w('#charmsSelectionStrip').collapse();
calcAndShowPrice();
$w('#addToCartStrip').expand();
$w('#reviewBraceletText').enable();
$w('#addToCartButton').enable();
};
```
**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.
```javascript
function calcAndShowPrice() {
let price = selectedBracelet.price;
selectedCharms.forEach(charm => {
price += charm.price;
});
$w('#price').text = price.toString();
};
```
**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.
```javascript
export async function addToCartButton_click(event, $w) {
let itemsToAdd = [{ productID: selectedBracelet._id, quantity: 1, options: {} }];
selectedCharms.forEach(function (charm) {
itemsToAdd.push({ productID: charm._id, quantity: 1, options: {} });
});
let res = await $w('#shoppingCartIcon').addProductsToCart(itemsToAdd);
};
```
**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
* Open [this example](http://editor.wix.com/html/editor/web/renderer/new?siteId=11e2a942-7c54-4bbb-9ffb-cce15e010fb1&metaSiteId=635e3b99-e23b-428e-8947-0fd14be46ddc) in the Editor to work with the template.
* Publish the site and refresh your browser so the Stores collections appear in the Database.
* Try other Velo Stores examples:
* [Adding a Related Products Area to a Wix Store Product Page](https://support.wix.com/en/article/adding-a-related-products-area-to-a-wix-store-product-page)
* [Adding a Wishlist to a Wix Stores Site](https://support.wix.com/en/article/adding-a-wishlist-to-a-wix-stores-site)
* [Adding a Product Configurator to a Wix Stores Site](https://support.wix.com/en/article/adding-a-product-configurator-to-a-wix-stores-site)
* [Adding Ratings and Reviews to a Wix Stores Site](https://support.wix.com/en/article/adding-ratings-and-reviews-to-a-wix-stores-site)