This tutorial walks through how to create a shopping cart, including the ability to add and remove items from a cart, as well as the calculation of totals.

Here is a sample, which you can copy into your own account: https://app.atomic.io/d/uQcldF7Yq70b
 

Step 1: Copy the sample prototype

Add the sample to the project that you wish to make your cart in: https://app.atomic.io/d/uQcldF7Yq70b

Once it is copied into your project, select ‘Edit Now’, then click on the Atomic logo in the top left to get back to the project. 

This is the most efficient way of copying the required variables, and provides you with some pre-formatted components to use.
 

Step 2: Add your data to a Google Spreadsheet

The sample you copied uses a Google Sheet to populate the items available to be added to the cart. You can view the original sheet here: Shopping Cart Sample Data. The spreadsheet holds all of the content for each of the items, including pricing, product details and a URL to an image of the item.

If you’d like to add your own data you can create a new Google Sheet. If you don’t have a Google account already, you can sign up to get a free one.

Once you have the data in the spreadsheet, import it into your project:

  1. In your project, select the ‘Data’ tab.
  2. Select ‘Import Data’ and follow the instructions to link your Google account and import the spreadsheet.
  3. If you make any changes to the spreadsheet, sync the changes back into Atomic by pressing the ‘Sync’ button available.

Tip: If you're linking to images in your data sheet, we recommend ensuring the URL points to a secure HTTPS URL, not a HTTP one.

See more on: Using data in your prototypes
 

Step 3: Display a list of products using components

In the project, create a new prototype. 

Rename the page the cart will appear on to 'Products'. This will ensure the script added in step 5 works correctly. 

Add the elements that will make up each item tile to your canvas. 

Tip: if you are using an image, then the placeholder for the image needs to be an image, not a rectangle. Resources like placeholder.com make it super simple to find a placeholder image you can use. 

Select all of the elements that make up the item tile, and then click the ‘Create reusable component’ button in the top toolbar, or use the keyboard shortcut ⌘3.

See more about components in this help article: Working with Components

Duplicate the component for each item you’d like to display on the page. For example, if you’d like the page to display 9 items, then duplicate the original component 8 times. 

Select all of the instances of the component and wrap them in a  scrolling container by selecting the ‘Create: Scroll’ tool at the top of the screen.

Reorder the elements so that they go from first to last in the layers panel on the left hand side. If you added instances of the component from first to last, they will be in last to first order and so will need to be re-ordered. You may like to number the instances different names to make this task easier. 

Connect your component instances with the data you’ve set up by selecting the container, then select your data source from options available under ‘Data’ in the properties panel.

Check the box to ‘Maps rows to child elements’. This will distribute a row of data to each data-enabled element within your container.
 

Step 4: Populate item components with data

Because we have duplicated the same component multiple times on the page, we only need to complete this step once, for one instance, and the changes will be applied to all components. 

Double-click on one of the item components to open it, then select all the text elements that you would like to populate with data. 

Select the text elements, and then in the properties panel, set the Content property to ‘Set from data column’, then select the data sheet you would like to connect to the prototype. 

Now select each element individually, and set to the correct column (e.g. for the price, set the ‘Column’ to be the column in your spreadsheet that holds price information). For example, select your placeholder price element and select ‘Price’ in the drop down. 

Now select all the text elements again, and set the source of each to ‘Inherit from parent. The specific column we’ve just selected will be remembered. 

Now select the image and complete the same procedure:

  1. First set the ‘Data’ to your data source
  2. Then set the ‘Column’ to the correct one for your images
  3. And finally, set the ‘Data’ back to ‘Inherit from parent’

Finally for this step, back out of the component by selecting ‘Back’ in the top left. 

See more on: Using data in your prototypes
 

Step 5: Add placeholders for cart items

Select the 'Place a Component…' tool from the main toolbar, or use the keyboard shortcut ‘C’ to open the component picker.

Select the "Item" component to place it on the canvas. We’ve made this part easy for you by making a component with built in functionality. 

This component includes images and details linked to the sample data sheet. If you are using your own data sheet, you’ll need to update this component to link to your data, replacing the details of each page with you own. 

For example, on the page '1' add the elements from the first row of data in your spreadsheet. 

Back out of the component, so you are on the 'Products’ page. 

Finally for this step, rename the component instances ‘slot1’, ‘slot2’ etc for all of the placeholder cart slots.
 

Step 6: Add JavaScript

Every item can be selected, and so clicking any of them will cause the cart on the right to update. This is achieved by fetching the item’s value (from the data connected to the prototype) and passing it to some simple JavaScript. The script handles the logic and even calculates the total amount. 

To add the code, add a Timer based page action (at 0ms) to run the following JavaScript:

/* Set up a few default values */
$p.shoppingSheet = data("Sheet1: Dynamic Shopping Cart Data - Copyable"); // fetch spreadsheet data, store in an array
$p.maxCartSize = 8;
$p.discountMultiplier = 0;
currentCart = [];

/* Add a new item to the cart */
addItem = function ($p, currentCart, newItemId){
  // Do nothing if the cart is full, but if there's room:
  if (currentCart.length < $p.maxCartSize) {
    // Add the item to the cart array
    currentCart.push({
      "id": newItemId,
      "Price": $p.shoppingSheet[newItemId-1].Price.substr(1)
     });
    itemsCount = String(currentCart.length); // Calculate how many items are now in the cart
    updateCartCountLabel(itemsCount); // Call a function to update the label that shows num of cart items
    recalculateTotal($p); // Call a function to recalculate the total cart value
    state(["Products", "slot" + itemsCount], newItemId, "slide-up", "ease-in", 300, 0); // Show the new item the correct item component
  }
}

/* Remove an existing item from the cart */
removeItem = function ($p, currentCart, removeItemFromSlot) {
  currentCart.splice(removeItemFromSlot - 1, 1); // Remove the specified item from the cart array
  itemsCount = String(currentCart.length); // Calculate how many items are now in the cart
  updateCartCountLabel(itemsCount) // Call a function to update the label that shows num of cart items
  recalculateTotal($p, currentCart); // Call a function to recalculate the total cart value

  // Refresh cart tile states to match adjusted cart
  for (let index = 0; index < $p.maxCartSize; index++) {
    if (this.currentCart[index]){
      newState = String(this.currentCart[index].id);
      state(["Products", "slot" + (index + 1)], newState, "slide-up", "ease-in", 300, 0);
    } else {
      state(["Products", "slot" + (index + 1)], "none", "fade", "linear", 300, 0);
    }
  }
}

/* Update the text label that displays count of cart items */
updateCartCountLabel = function (itemsCount){
  if (itemsCount == 1) {
    text(["Products", "itemCount"], itemsCount + " item");
  } else if (itemsCount > 1) {
    text(["Products", "itemCount"], itemsCount + " items");
  } else if (itemsCount == 0) {
    text(["Products", "itemCount"], "0 items");
  }
}

/* Calculate the total cost of the cart */
recalculateTotal = function ($p){
  let workingTotal = null;
  // Fetch each cart item's price, add them up
  for (let index = 0; index < currentCart.length; index++) {
    workingTotal = workingTotal + Number(currentCart[index].Price);
  }

  $p.displayDiscount = "-$" + Math.round(workingTotal * $p.discountMultiplier); // Calculate the total discounted amount
  $p.displaySum = "$" + Math.round(workingTotal - (workingTotal * $p.discountMultiplier)); // Apply any discount and format nicely, pass to $p.displaySum
}

/* Apply or remove the coupon discount */
validateCoupon = function ($p){

  if ( $p.coupon.match(/smartypants/i) ) { // If user has typed: smartypants (case insensitive)
    $p.discountMultiplier = 0.2; // Enable the 20% discount
    state(["Products", "Discount"], "Smartypants"); // Change state of "discount" component to reveal discount amount

  } else if ($p.coupon.match(/vip/i)) { // If user has typed: vip (case insensitive)
    $p.discountMultiplier = 0.45; // Enable a whopping 45% discount
    state(["Products", "Discount"], "VIP"); // Change state of "discount" component to reveal discount amount

  } else {
    $p.discountMultiplier = 0; // Remove the discount
    state(["Products", "Discount"], "none"); // hide the component called "discount"
  }

  recalculateTotal($p) // Call the function that updates the cart total
}

See more on adding timer page actions here: Page based actions
 

Step 7: Add a script to add items to the cart

Now we need to add a script to each item to be trigger when it is selected. 

Select the first item on your page, add a ‘Click or Tap’ event, set the ‘Action’ to ‘Script expression’ and copy and paste the following script: 

addItem($p, currentCart, 1);

Now repeat this for each item in your prototype, but replace the ‘1’ with the next whole number (e.g. addItem($p, currentCart, 2); for the second, and addItem($p, currentCart, 3); for the third).
 

Step 8: Add a script to remove items from the cart

Similar to step 5, we need to add a script to each placeholder component in the cart, but this time for removing the item from the cart. 

Select the first placeholder item in your cart, add a ‘Click or Tap’ action, set the ‘Action’ to ‘Script expression’ and copy and paste the following script: 

removeItem($p, currentCart, 1);

Now repeat for each item in the cart, but replace the “1” with the next whole number for each slot position in the cart (e.g. removeItem($p, currentCart, 2); for the second slot, and removeItem($p, currentCart, 3); for the third slot).
 

Step 9: Add total cost and item counter elements

Add a text element on the canvas to keep track of the total for the order. Rename it to ‘totalCost’.

Connect this text element named ‘totalCost’ to the ‘displaySum’ variable.

Add one more text element to record the number of items in the cart. Name it ‘itemCount’.

Leave the contents of this element blank, so nothing is displayed until an item is added to the cart. 

Both of these text elements will dynamically update when that number changes.
 

Step 10 (optional): Add a discount component

Place the ‘Discount’ component from the sample onto your canvas. This component has 3 pages.

Now we add and format text input to capture coupon code. Add a text field and connect it to the variable named ‘coupon’.

Add a text input. Select the input on the canvas, and then add an action on ‘Keypress’ to run the follow JavaScript:

validateCoupon($p);

You can add some placeholder text to the input field, if you like. E.g. ‘coupon code’.

There are two coupon codes that have been added by default:

  • vip
  • smartpants

You can edit the text and discount amounts for these in the code in step 6. If you do this, in the discount component, duplicate one of the current pages and refactor it for the new discount:

  • Change the name of the page/state to match the new coupon code
  • Change the text to match the new coupon code. E.g. return customer - 10% off

 

Step 11: Preview

Use the keyboard shortcut Command + Enter, or select ‘Preview’. Try adding and removing items from the cart and watch as the total updates automatically.

Did this answer your question?