📒 What is the best way to publish a list of objects to bubble?

I’ve built a “shopping cart” like functionality in the past using Bubble’s database and overall didn’t like the user experience. Perhaps I went about it the wrong way but here are the cons I ended up with (skip past these bullet points to get to my actual question):

  • Updates to the user cart were slow (needing to wait for the database to update in order for the cart to update). Granted, when I say slow, I mean it takes a half second to a second… so it’s not a show stopper but it’s not great.
  • Showing order totals and quantities is clunky - needing to set element states for quantities and totals on item groups in a repeating group, and then summing across the repeating group to get an order total.
  • Saving carts to the database is nice because you can email existing customers with abandoned carts to increase conversion BUT Bubble does funky things with associating carts in the case when a pre-existing user is logged out, then creates a cart, then signs in (In my case the cart would “vanish” because Bubble wouldn’t intelligently recognize the signed in user as the one that had just been signed out, despite it intelligently working in cases where users did not have a pre-existing account)
  • Finally, saving abandoned carts server side creates the janitorial requirement that I’d need to regularly flush stale carts. Not really an issue, but this gets more complex when trying to build a marketplace using Bubble (where you’re keeping track of multiple sellers plus all of their respective customer’s abandoned carts).

So I’d much rather save carts on the user’s device via cookies. Shopping cart management is insanely easy to achieve in plain javascript - below two functions addItem and removeItem handle everything:

V7U6twhCrR

As you see, we are able to easily output a list of objects which I want to save to a user’s “Order” thing. What’s the best way to publish this list of objects to Bubble? Three lists? One for ItemId, one for price, and one for quantity? Ultimately, I want my orders database table to look like:

image

4 Likes

Hi! Been there, thought that. This point is a bit of a pain for me too, because for example whenever you publish a list of texts (product name) or numbers (a quantity) to Bubble it cannot contain duplicates. This makes any easy JS handling useless. Unless…

I’ve been thinking of using offline in-browser database management systems like http://hood.ie/ or just https://pouchdb.com/ for more complex stuff (probably not needed in this case!), however there’s the limitation when dealing with Bubble’s native lists.

I haven’t really tinkered with it yet (it’s on my “someday” list), however I think that if we can get to pass an encoded string containing the values (objects) as a Bubble native single text (not a list, just a string) and at the workflow level have a decoding action that is able to get that single string/text and output objects one by one on a self scheduling (looping) scheduled workflow action… we could have an efficient way to handle it even server side (within Bubble’s app).

The same solution would be able to, when working with elements and displaying stuff for the users on the front side, publish a single string to several Bubble elements and having each of these elements decoding it depending on their cell index. Or something else like that. That solution would be infinitely scalable.

I know that this feels a bit different from just publishing a list to Bubble, but I’m saying this because we just can’t publish a list of quantities, Bubble would eat (remove) any values that are not unique and we would end up with an incomplete list.

However, if you’re not having too many items, you could just have a plugin element with, say, 60 states and publish to all of them individually, being 20 states “item ID X”, another 20 “item name X” and the remaining 20 “item quantity X”, with X being the index position of the item, and get the data sources of the elements in the repeating group to listen to the states with an index equaling to their cell index. But let’s not get started on the hassle that maintaining this would be.

These are possible ways for us to do client side experiences like a shopping cart that works instantly (and for free in terms of app capacity) by not needing to touch the database for non unique values.

Phew.

1 Like

Hi @vini_brito

To make it unique, can you simply add some extra id at the end of a field, like ‘my_table_unix4234239933’ to make it unique? simply replace numbers by unique Unix date? When retreiving, remove the extra with some regex filter?

1 Like

Vini! So great to hear from you (sorry for the delay - I’ve been on holiday)! I’m curious what options (if any) you know of that could publish objects to bubble when the list of objects does not contain duplicates. I ask because as far as I can tell, a shopping cart summary would not contain duplicates since it would have one object per unique bubble item. Oh, wait a second - what you’re saying is that the duplicates could appear in the quantity or totalPrice “sub lists”… shoot… you’re right. So then I wouldn’t be able to export those to Bubble. That’s frustrating.

That’s a real bummer because Bubble can parse JSON coming from remote servers quite well. If only it could parse JSON from a client - that would be brilliant. After all, JSON does stand for Javascript Object Notation. Perhaps @cal could offer some guidance here?

1 Like

This has been a VERY top of mind item for me for a few years. I have a system that creates a Data Object for every ‘item’ added to a ‘cart’. I have optimized it as much as possible, but it is beginning to slow things down, and I feel any Cart experience should be as quick as possible to reduce abandonment.

So I have off and on been playing around with solutions, but never actually completed any single method. I have tried @JohnMark’s method, and a similar one using the Toolbox Plugin; turning the cart list as a single text field in JSON format, and then using the Javascript to Bubble (also in toolbox) to parse it back. Both of these seemed promising and quick, but my specific use case made these hard to implement, as I needed a Data Item to be created for each Cart Item for discounting purposes

So I have been looking into the BDK plugin from @gaurav, specifically this one: https://bubble.io/page?type=page&name=bdk_utilities_easy_list&id=bdkdemos&tab=tabs-1

It seems that you would be able to simply add and remove Duplicate items in a Cart. Which for my use case should work well. Testing this out soon so I will report back afterwards

3 Likes

Hmm, I took a look through the BDK plugin and am not sure “easy_lists” are the way to go. I could be wrong but I don’t see how to manipulate them to display price subtotals, aggregate quantities, total price, etc. @gaurav, any pointers?

All that said, I made a plugin that can update a cart stored as a cookie. It can add and remove items as well as calculate quantities, item subtotals and order totals - all in real time! (note: the item quantities shown on the app are only state driven… not reading from the cookie :frowning: )

35oIJFhqdd

The only thing I can’t figure out is how to get it to send these cart objects back into Bubble and saved as things. That would be a dream! Can @cal, or @sam8 or @peterj explain how this could be done (or whether it’s impossible as Vini has said)? I would Platonic love you forever :slight_smile:

EDIT:
And I’ll add, if this can’t be done, can you please advise as to the best way to create a shopping cart since creating them in Bubble is actually quite unintuitive. Many users share my pain. For example:

I can go on and on… here’s the pile of over 143 shopping cart related questions on our forum… The point is People use Bubble to sell stuff. There are 12 Stripe Plugins which collectively have been used over 24,300 times. And look at this list of top plugins by usage:

  • Ionic Elements - 47,655
  • API Connector - 42,286
  • Google Material Icons - 32,277
  • Toolbox - 31,794
  • Slidable Menu - 21,687
  • Random User Generator - 21,356
  • Multiselect Dropdown - 17,207
  • Stripe - 15,442
  • Draggable Elements - 14,454

Most of those plugins have to do with just making an app look pretty - visual sugar. Filter those out and the official Bubble Stripe plugin is effectively the number one used plugin on Bubble. Ergo “Selling stuff” isn’t just a use case of Bubble, it is the use case.

So for the love of Zues make making shopping carts easy!

3 Likes

You can’t export objects as “Things”, but you can export them as parallel arrays of primary Bubble datatypes. It is then up to the user to Create New Things from those outputs.

Plugins can neither directly read, modify, nor create Things in the database.

BTW, I, too am vexed by the constant cries for a way to create functional shopping carts in the page (of course, if you’re willing to do things “the Bubble way”, this is a non-issue [create an Order object consisting of Line Items which consist of a Quantity and Product], but some folks can’t abide the “blue bar of death”).

The next version of List Shifter addresses this by allowing arrays (lists) to be used as arguments in the Process List action.

(The issue with shopping carts being that even if you create an Order object consisting of Line Items, you still have a hard time doing sub-totaling and cart totaling unless you’re willing to write those values to the database which is, of course, unnecessary. But all of this is quite easy in any “normal” language. The missing link in Bubble is the lack of user-available .map() type function [or, indeed, any type of looping]… which is totally weird and stupid, of course, as Bubble does .map() all over the place [e.g., as when you reference Some_List_of_Things’s Field… and get a list of those Fields… Bubble is literally doing something akin to Some_List _of_Things.map(thing => thing.Field), right?] But the user has no way to do something more advanced like, for example, Some_List_of_Things.map(thing => thing.Field * 2) OR, more importantly, Some_List_of_Things.map((thing, i) => thing * Some_OTHER_List[i]).)

The next version of List Shifter gives that, which is very, very cool.

2 Likes

@zelus_pudding
I think you might be complicating it much beyond requirement :slight_smile:
The very easy way to implement shopping carts is using the repeating group tools plugin + from bdk utilities in my view. I know many people use the plugin for this very purpose.
You should be able to do it without any creation / storing of line items etc. The RG tools can basically create your line items on the fly.

For example, take a look at the demo 2 and the corresponding editor setup

You can get the line item data out via rg tools. And if one of the things you get out is the item number of that cell, you can use that to simply do whatever you want with the data. For example, run the List processor from BDK utilities on the entire list to convert the cart to order. Or use transformlist to convert to a json and store it in your database etc.

Cheers,
Gaurav

3 Likes

Hi @zelus_pudding ,

Thanks for pointing out some issues with the shopping cart widget! Here are the changes we’ve made:

  1. Optimized how the order is updated (instead of doing a search for an order every time a quantity is changed, instead it now references ‘Current user’s Order’)
  2. Disabled the buttons to change the quantity of the item ordered while the previous change is still processing (in case the user wants to click those buttons really fast but for whatever reason the database takes a while to update)

More generally, one of the beautiful things about Bubble is how low-level it is - this means that you can build whatever functionality you want, you have total control. So if you want a shopping cart that works differently than other shopping carts, you can do that. The downside is that it ends up being more complicated to set up than something where you just plug-in an out-of-the-box shopping cart.

As a sidenote, we do plan to introduce a shopping cart as part of our Canvas framework, at some point.

1 Like

@zelus_pudding: I made a thing for you…

11 Likes

This is very cool! You make an interesting point about how the native “Bubble way” is arguably better since it’s not exhausting capacity on server side data processing AND because it’s effectively the same speed. So I’m super curious what your exact setup for a “Bubble Way” cart is. I hunted for your editor url but from the looks of your video it doesn’t appear public…poked through your demo video starting from here up to here but my eye didn’t catch it in their either. Can you share what that setup is (Our point me to the link I may have glanced over)?

I’m really curious to see this native way, because since you pointed out that we can output lists with duplicates in them I actually implemented a client side cart that does exactly that. It’s neat because it stores the cart as a cookie and I can do any calculation or fancy volume pricing stuff… but it’s a bit of hack stitching it together with Bubble… requiring a workflow that runs every 0.2 seconds to input the current date into the plugin so as to fetch the current cookie values (because visual elements only update if a field’s value changes… but it can’t sense when a cookie’s value changes).

But in general, I’m always open to better ways of doing things.

Thanks for all of your input! And the cool plugin update!

2 Likes

Hey, @zelus_pudding: Editor URLs here:

“List Shifter” (no database) way:

“Basic Bubble” way (well, also uses List Shifter, but just as a container for lists):

Regards,
K

6 Likes

I’m always impressed by your curiosity and ingeniousness :relieved:

Yup, you were right. I’m kicking myself for that simple code :smile:

The fun thing is, and also my main takeaway: you found out that Bubble doesn’t cleanses duplicates when a list touches the database, it does so when you use a few specific operators. So what you did is to pluginify those operators, sidestepping their Bubble native versions at all. Is that correct?

So if I use “set list” I’ll be always safe?

P.S: I’m still trying to figure out how did you created the duplicates with List Shifter in the first place? The step by step workflow mode breaks the page :roll_eyes: so I can’t see what happens in what order.

I should note: The JavaScripty/no database way relies on some new features of List Shifter, which is basically its own no-code environment and can be a little confusing without familiarity. It’s more JavaScripty than Bubble. When you examine a PROCESS List action, think JS and you’ll understand what’s going on more (the operator dropdown shows literally the code that will be run).

The main point of the native Bubble way is that people mis-think carts. A cart IS NOT a list of products onto which we graft a quantity, etc. A cart is a means to building an ORDER.

As such, a CART contains either an Order (or, as I’ve done here) the LINE ITEMS that compose an Order.

A Line Item is not a Product. A Product is part of it, of course, but the taxonomy is basically:

Order

  • Line Items
    • Quantity | Product | Price | Subtotal

Of course, a Product has a Price, but we should pull Price out when we create a Line Item because a Product’s Price may change over time. Subtotal is a derived value and is just Quantity * Current Price. One can choose to precompute it or to compute it at Line Item creation time (as long as we’ve pulled out Price at the moment the User places their Order… the point being that the Subtotal is fixed and will not change in future if Product’s Price changes).

1 Like

Apart of what I said above (please please answer that :relieved:), when I first tried to build orders I tried that way you mentioned it should be. But then I got stuck at the duplicates part, not being able to create and manage lists with duplicates and then went with the less efficient way.

That’s why we all here are interested in that!

1 Like

Hey @vini_brito: Glad you found that interesting! :slight_smile:

As for Bubble lists: YES, a Bubble list of any type is just its JavaScript equivalent. So, just as in JS, I can say:

a = [1,1,1,1,1]

And we can push that array to a plugin’s output. (Or, in Run JavaScript, I could just return [1,1,1,1,1] ). What you will see is that the returned “list” is an array(5) full of “1”.

It is only when we do a list operation on it that our array of ones transforms into an array(1) of a single “1”.

The reason this is not obvious (beyond not being documented) is that, in vanilla Bubble we cannot ever create [1,1,1,1,1]. We will always wind up with [1] because there are no constructors beyond “add list” and “plus item”… which de-dupe the array.

As for List Shifter and duplicate array elements: List Shifter’s PROCESS List function takes any of List Shifter’s internal arrays (which can be the “Original List”, “Shifted List”, “Processed List” or “Do Once” (which is just a single-element array that contains [0])) and loop over them, doing something for each iteration.

So, let us say that List Shifter’s “Original List” is an array of 5 Products (Product being a Bubble object). We can, in the PROCESS List action (if Process Action Type is set to number) do as follows:

STEP 1:

  • We can leave operand X empty
  • We can leave the Operator dropdown empty
  • We can enter the numeral 1 in Operand Y

(What this does is to say, “Simply return the number 1 in this step.”)

We can then set “Push to Processed List” to “yes”.

What this will do is – for each iteration – push the number 1 on to the Processed List. So we get (for each step):

Processed List.push(1)

So, at the end of iteration (over 5 items) we have the array:

[1, 1, 1, 1, 1]

And this gets published to List Shifter’s “Processed List” output.

We can also do things like randomly access the elements of Processed List and set them to new values. This is how the “in the page” version keeps track of the Quantities in that scenario.

1 Like

When we do things “the Bubble way” we face the opposite problem: We create a Line Item (which is, of course, unique… because we asked it to be). For example, the User may add “Canned Cat” to the cart. They may again hit the “Me Want… Add to Cart” button. IF they do this, this will (unless we do something about it) create a NEW Line Item for Canned Cat… Because each Line Item is unique.

However, we can check if there is already a Line Item whose Product’s contains “Canned Cat”. If so, we don’t create the new Line Item, we instead increment the existing Line Item’s quantity by 1. I’m pretty sure that my demo app does this…

Thanks for sending those! Am boarding a plane at the moment so will definitely check those when I get the chance. Really appreciate it!

This is sooo cool! I ended up creating my cart as a client side plugin which saved the cart state as a cookie. Then used your List Popper to push a completed order into bubble. I copy and pasted most of your server side actions and it just worked on the first go! Thank you so much for chiming in - just payed it forward with a karma $ donation. Thank you again so much (and being a great Bubble contributor in general) :slight_smile:

5 Likes

Hey @zelus_pudding: Much appreciate the Karma-Ware contribution and I’m glad List Popper was helpful!

2 Likes