Repeater - add to cart - calculate the final price


#1

Hi everyone! :sunny:

I’ve a problem that i haven’t solved yet…hope someone with more experience than me can help! :slight_smile:
I’ve a classic e-commerce…with 2 repeaters, one for items that you can buy, the other with the items you put in the cart.
I’m able to update rows, send the correct quantity of items to the repeater cart for each individual product, and the same for the price of each item ( multiply price of item * number of the product ).

MY BIG ISSUE IS :frowning: : how can i bring each “final price” of each item into the repeater cart and put all of its in one variable ? ( so i can calculate the total price and the total price with VAT)

Hope someone will help me.
Have a good day everyone :ok_hand:


#2

it might be best if you can upload your .rp file here. That is usually the easiest and fastest way for others here to help you.

It sounds like you can do this already, but I’ll touch on details of this later on…

In general, there are several basic methods to calculate a tally of repeater row values, depending on how you structure your repeaters and handle user interactions (adding/changing/choosing items) as well as if both repeaters are on the same page or different pages. You can store totals in global variable(s) or the text value of widget(s) either inside or outside the repeater–but if you need to refer to these values on another page then you must use global variables.

The widgets which show these totals should be outside both repeaters.

Here are some basic methods to keep track of totals. Each has its own advantages and disadvantages.

  1. Update a running total “on the fly” as a direct result of user interactions in the “product catalog” repeater–typically via the Click or Tap event of a widget in the repeater, like a button, or Text Changed event of a Text Field. As a very simple example, let’s say you have a repeater with two columns in its data sheet: “Product” and “Price”, and in the repeater cell, a widget for each of these, along with an “Add To Cart” button.
  • You can create a global variable to store the running Cart total, let’s say it is named, “VarCartTotal”. (Its default value is zero, which you can set either in the Page Loaded event or the repeater’s Loaded event.)
  • The “Add To Cart” widget has a Click or Tap which would include a Set Variable Value action like, "Set Variable Value of VarCartTotal to [[VarCartTotal + Item.Price]]" (along with action to add or update a row in the cart repeater.)
  • If you have a widget showing the number of items and/or a repeater column to store this number, you can have a set of conditional cases to handle a change to 1 (e.g. first time “Add To Cart” is clicked) --to add a row to the cart; and greater than 1–to update an existing row in the cart; and less than 1 (or “equal to 0”) --to delete a row in the cart repeater. For example,
    If text on MyProductCount equals "1" Add Row to CartRepeater
    Else if text on MyProductCount is greater than "1" Update Row of CartRepeater
    …(with rule like “[[TargetItem.Product == Item.Product]]”
    Else if text on MyProductCount is less than "1" Delete Row of CartRepeater
    …with same rule to match rows.
  • This method is pretty straightforward, but it will fail if you alter the catalog repeater in any way, such as sorting, filtering, adding or removing rows, etc. because each of these actions would trigger the repeater’s Item Loaded event, thus resetting everything to default, thus losing any user selections.

  1. Or you can use the Item Loaded event with conditional cases. This lets the repeater automatically calculate totals in a self-contained way. This requires a column per each value you need to track–like the number of items per product. Instead of just directly setting the text value or global variable value when an item is added/edited, you update the row in the same repeater (as well as adding/updating a row in the cart repeater.) This method takes a little more setup time and forethought, but is more reliable and flexible as it supports sorting, filtering and other catalog changes.
  • The “Add To Cart” button would have an action like,
    Update This Row …where you select the column to update, like “Count” with expression like, [[Item.Count + 1]]
  • The repeater’s Item Loaded would have a set of conditional cases like,
    If [[Item.isFirst]] equals "true" Set Variable Value of VarCartTotal equal to "0"
    If true Set Text (of your repeater widgets)
    Set Variable Value of VarCartTotal equal to [[VarCartTotal + (Item.Count * Item.Price)]]
    • Thus, every time the item repeater is updated it runs through each row, first initializing the running total (VarCartTotal global variable) to zero, then adding the cost of each item (multiplied by the selected number per item)
    • You could also build in the logic to update the cart repeater, here in the Item Loaded event rather than the “Add To Cart” button (and whatever else controls you might have like ‘+’ and ‘-’ buttons, text entry, a “Remove” button, etc.)

  1. Or, you can calculate the “final price” per item and the totals (price, VAT, price with VAT) all in the cart repeater, based purely on the items in the cart. This method works if both repeaters are on the same page. If the cart repeater is on a different page, the product repeater (or a “mini cart” repeater on first page) would first need to set some global variables for the totals.
  • The catalog repeater adds/updates/removes rows to the cart repeater as described above. But, it is not concerned with any totals. This approach can help keep the functions and logic separated, which should be more reliable, easier to debug, and more reusable. So basically, the function of the catalog repeater is just to show products (along with names, prices, images, descriptions etc.) and allow them to be added to the cart–that’s it. The function of the cart repeater is to show selected products and calculate totals (as well as change counts of products, remove them, etc. as needed)
  • The cart repeater would have columns for (at least) Product, Price, Count.
  • The cart repeater’s Item Loaded event would contain the conditional cases to initialize the total value(s), and update these totals for each row (using the same logic as shown in method 2 above.)

  1. If you have a catalog repeater on one page (or multiple pages) and a cart repeater on its own separate page, you could also set up one global variable per possible product, or use one global variable to store an array of selected products, their prices and item counts. Now, Axure does not support true arrays (unfortunately) but you can kind of manually create one as a “hash string” and then on the cart page you can parse this string to construct the cart repeater and its running totals. This is a fairly advanced method, so I’ll just point to a forum thread which demonstrates it. This method works if you have many pages that need to refer to “cart details” --such as multiple catalog/product pages, and/or separate “checkout” pages that might need to access, edit and/or recreate a cart.

Good luck, and if you have any specific questions or would like to see some examples of these methods, reply here and I’ll post some examples.


#3

Hi mbc66,

First of all, really thank you for your reply! I’ve really appreciated :pray:
I have tried experimenting with the second and third methods you explained, but sadly something is still not working for me…
If you would like to post some example, i would really love it! meanwhile, i attach my file, so you can see it if you want…
Unfortunately I have only been using axure for a few months, and I still struggle to understand some concepts.
I hope to hear from you soon!


https://x0sqih.axshare.com/#id=zednrf&p=sandwhich_page___correct_-local_var


#4

Well, this is quite an ambitious prototype for only using Axure a few months. You’ve done well so far! Repeaters are advanced–some of the most complicated things you can do in Axure, and take a lot of time and experience to get used to using–and even then, usually require a bit of trial and error to get them working properly.

Here is an updated file (too large to post on this forum) with a summary of what I changed. I basically use the third method as outlined above.

In the ++Sandwiches repeater:

  • I changed the unused C_TotalPrice column to C_inCart, with possible values of “true” and (not true: so “false” or blank). This helps handle button clicks when a row needs to be added, updated, or deleted in the cart repeater.

  • I updated the Set Text so the price value includes a ‘$’ --in general it is best to keep the repeater datasheet numeric values as pure numbers and then format as needed when setting the text. This makes math with them much easier.

  • I changed the Click or Tap events for the (-) , (+) and Cart buttons.

    • First of all, you don’t need to set text of a repeater widget prior to updating the row, because the text already gets set in the Item Loaded event.

    • I removed all the Set Variable Value actions, so the Cart repeater can handle these in a more reliable way.

    • It has been awhile since I’ve done e-commerce stuff, but I recall usability issues when there is both an “add to cart” button and buttons to change the quantity. Things like, how do you handle a cart button press when quantity is “0”? (…and looks like you chose to add the item to cart, but the quantity in the product repeater doesn’t get updated.) Similar for decreasing amount to “0” --users expect it would remove the item from the cart without having to press the cart button or go to the cart. …etc.

      • I chose to automatically update quantity to “1” if user presses cart button first.
      • Likewise, if an item is in the cart and the quantity is decreased to “0” that item gets removed.
      • Basically, all this just means having a few conditional cases on these buttons’ interaction code.
      • Obviously, you can adjust the interaction model as you need.
    • The cart button has 3 cases:

      • If Item not yet in cart and quantity is “0”

        • Add a row to the cart repeater (with item quantity of “1”).
        • Then update “this” row in product repeater to show quantity of “1”, and set the C_inCart column to “true”. This must be done after updating the cart repeater, because as soon as it gets called, everything in this repeater–including this button–gets reset. So, if the order of these two actions were reversed, the second–Add Row to cart repeater–would never get called.
      • Else if item is not in the cart (and thus quantity greater than 0)

        • Add row to cart repeater, using the expression,
          [[Item.C_Price * Item.C_quantity]]
        • Then update “this” row to set the C_inCart column to “true”.
      • Else if item is in the cart already, just update the “Price$” column in the cart repeater.

        • (It turns out this case is not needed if the (-) and (+) buttons update the cart quantities directly. I kept it just in case.)
        • I use this expression in the Rule field to ensure the correct row in the cart gets updated:
          [[Item.C_title == TargetItem.Name$]]
          …where “Item.” refers to “this” repeater and “TargetItem.” refers to the "targeted’ repeater–in this case, the cart.
    • The RemoveQuantity button has three similar cases:

      • If item is in cart already and quantity is greater than 1, update rows
      • Else if item is in cart and quantity is 1 (thus now reduced to 0), remove the row from cart
        • …Except I discovered the totals don’t get properly updated if the row is simply removed. So, first I update the row in the cart to set the quantity to “0”, which triggers proper calculation of totals (in the cart), then Wait 10 ms (to ensure it has been updated) then Delete Row from cart repeater, then Update Row in the product repeater.
      • Else if item is not in cart yet, just update this row to decrease the quantity.
        (This would only happen if user pressed (+) more than once, then pressed (-), all before ever pressing the cart button.)
    • The AddQuantity button has two cases:

      • If item is in cart, update rows in both repeaters
      • Else if not in cart, only update this row’s quantity
  • In the ++ShoppingCart_modal I added widgets for “Subtotal” and “VAT (15%)”, above your “Total”. All three of these values get calculated in the Item Loaded event of the cart repeater.

  • In the ++ShoppinigCart_Repeater I added a few cases to Item Loaded to calculate totals:

    • Case 1, initialize count
      If [[Item.isFirst]] equals "true"
      Set Variable Value
      NumbersOfOrdersVar to "0"
      TotalpriceVar to "0"
    • Case 2, (always)
      If true
      (set text, set image)
      Set Variable Value
      NumbersOfOrdersVar to [[NumbersOfOrdersVar + Item.Quantity$]]
      TotalpriceVar to [[TotalpriceVar + Item.Price$]]
    • Case 3, show the count and totals
      If [[Item.isLast]] equals "true"
      Wait 10 ms (this should ensure it happens last, after variables updated in case 2
      Set Text (of the subtotals and cart count)
      • The “.toFixed(2)” is a built-in function to set “two decimal precision” so the monetary values are always shown with two decimal places for the cents.


#5

First of all, really really thank you for your time and work!
it’s very complicated for me, but i’m trying to learn and understand the logic behind that.
I apologize for the response time, but i was very busy.
I would like to ask you a few things to better understand what u’ve done :sunny:
1)can you explain me the logic of item.isFirst and item.isLast on the item loaded event on the cart repeater? I’m also studying javascript for that, but unfortunately i’m still a noob and i really would like to understand.
2) so you can calculate the total price just by add it’s variable to the item of the repeater, and then set the text ?
3) why you’ve multiplied the totalPriceVar * .15 ?

I hope you will still be very patient with me, thank you again for your time!
I congratulate you for your skills :muscle:


#6

Yes, this is a way to identify the first row and the last row in a repeater, for the purpose of calculating a total based on the value of a column in the repeater. So, when the repeater is loaded, and every time it is “touched” --a row is updated, added, deleted, or if the repeater is sorted or filtered-- its Item Loaded event gets fired, which basically rebuilds the repeater. This Item Loaded event happens successively for every row (Item) in the repeater. To properly calculate a total value based on column data, it is necessary to first set the “total value” variable (i.e., TotalPriceVar) to zero (know as “initializing” a variable), then successively add the column data for each row to this variable, and then (if needed) do something with the total after all the rows have been loaded and all their data has been added to the total value.

“Item” is a pointer to the current repeater row. So, if a repeater has 3 rows, there are three unique “Items”. Each Item has many properties, such as the columns in the repeater datasheet. To access these properties, a “dot” (the period character: ‘.’ ) is used to connect the Item to a specific property, for example, [[Item.Column1]]. So, .isFirst and .isLast are two built-in properties of a repeater Item. It is a way to determine if the row is currently the first Item, and if the row is currently the last item in the repeater. Both of these are Boolean values, meaning they can only have one of two possible values: true or false. It may seem a bit odd to have to test if the first row of a repeater is really the first row, but realize the repeater can be sorted and/or filtered in many ways, thus changing the order of the rows as well as the availability of rows (in the case of filters.)

There are a lot of properties you can access for repeaters, as well as other widgets and “system data” like dates, time, browser window, cursor, etc. Click the “Insert Variable or Function…” link in the “Edit Text” dialog to browse and select them. Here is the Axure documentation for this:

…And yes, these are all using (at least based on) javascript methods, so it can be very useful to have an understanding of how javascript works. I’ve found that just googling “javascript” and whatever I want to do usually leads to a solution I can use in Axure, as well as explanation and examples for properties and functions I find in Axure. For example, “javascript get tomorrow’s date” or “javascript isFirst”. Furthermore, the answers posted on the Stack Overflow site are usually good and reliable.

Yes you can calculate the total price by:

  1. Initializing a variable to zero. (This ensures you start counting at 0.)
  • (This is why it is important to determine the first row of a repeater)
  • This variable can be a global variable.
  • This variable can also be the text value of any widget. i think of this as a “page-local variable”.
  • (There are advantages and disadvantages to using global variables and widget text values. Which you choose just depends on the context and your personal preference)
  1. Adding the value from a row’s column, once per row, for every available row, to the variable.

  2. Determining when the last row of a repeater has been added to this total, thus ensuring you have the complete “total” value.

  • Using the Item Loaded event with a conditional case of If [[Item.isLast]] equals "true" is a reliable way to know when all the available rows of a repeater have been loaded–thus all the data values have been added to your total value variable. In other words, to know when Item Loaded is done loading all the repeater rows. That is when you can do something with the total value, such as setting text in your cart.

Your original question asked how you can calculate the total price and the total price with VAT. I just used “.15” as an example, where the VAT is 15%. (Of course, you can use whatever percentage you need for this “VAT value”.) Typically, in a cart/checkout flow, things like taxes (and shipping, etc.) are shown under a (sub)total as a line item, then added to that total price to show a “total total” price.

Good questions, @Francesco! Hopefully you can understand my explanations here.


#7

Really thank you! You have been incredibly helpful!
As a last thing I ask you, can you recommend me some axure courses related to javascript functions?


#8

I don’t know of any courses or tutorials on javascript with Axure. You can find lots of good info and examples in this forum though. It is not officially supported by Axure, so you’re on your own if you use javascript injection.