Solved: list of texts containing duplicate items. App action history & 'back' button

Bubble’s inability to work with lists containing duplicate items has been a thorn in my side for some time. Without this you can’t easily construct a history / back feature on a single page application. I hadn’t found a solution on the forums so I’d thought to share my own tutorial.

The task:
Store historical actions (i.e. previously viewed pages, actions, etc) on a single page application without involving the database, custom JS, or URL parameters.

The problem:
If you want to store historical data (i.e. a list of previously viewed page views) as a state on the page, it would make sense to use a list of texts to store the data. Unfortunately, bubble doesn’t have an easy way to work with list of texts containing duplicate items, which makes it impossible to implement a page history and save it into a page state.
In general, being able to work with lists that can hold duplicate values has many benefits.

The solution:
Use bubble’s regex feature to work with a single text value, which is comma-separated. Regex can parse this comma-delimited text string into a list of texts which can hold duplicate items. The list of texts that is returned by regex can be worked on like any standard list in bubble.

Quick example: Navigating back

  1. Regex to get the text value of last item in your comma-separated list.
  2. Navigate to the value of last item
  3. Use find/replace to delete last item of the comma-separated text
    …The new last item in the list is what the 2nd to last text item was previously (and so on)

In depth step by step
This is as I’ve done it - other ways certainly possible/better for individual needs.

This step-by-step assumes a few things.

  • Your various page ‘views’ are already setup to show/hide based on a page state of type text (i.e. ‘current view’ = “Settings” )
  1. Create a page state called ‘navigation history’ of type text (do not set to a list)

  2. Create reusable custom page workflows for ‘Navigate to’ and ‘Go back’

  3. Custom workflow ‘Navigate to’ should have a text input so that text input can be used to trigger any new view from within the workflow.

  4. Navigate forward (store item into list)
    4a. Every time your workflow navigate to view is triggered the following workflow step will add a new item to the ‘Navigation History’ text (remember: this is a single text, not a list)

    If this is the first item, we want to store it differently than if it is 2nd-Nth item so we check if it is and use the conditional text option

    4b. This is the formatting for each condition.
    Notice that if the list is NOT empty, that we take the current value:
    page's navigation history
    and then concatenate:
    , page's current view
    onto the end
    i.e. page’s navigation history has the value of settings, account, payment, orders, settings indicating that those pages were visited in that order. Then, we concatenate the newest page orders as ,orders with the comma included to separate the new item to become
    settings, account, payment, orders, settings, orders

    The example image actually uses another concatenation, which is page’s current view | page’s sub view, which adds the additional feature to track two views together. It also adds complexity and is not necessary to store a list of repeating texts

  5. Navigating back
    a. To implement a back function we set the page’s current view to the last item in our history list.
    b. Use regex to extract a list of texts from values separated by commas inside single text stored state page’s navigation history

    c. Use the bubble list operations on the list of texts that is output by regex and get the last item. This is the most recent page view in our history

    d. The following regex expression will parse a comma delimited list. Bubble will then return as a list of texts

    Here is the selectable regex:

    e. To remove the last item in the comma-separate list of texts we use a find/replace

    f. Use regex to FIND the last item in the comma-separated list including the last comma.
    REPLACE that with nothing, thereby deleting the last item in the list.

    Here is the selectable regex:

  6. Done
    You have a way of storing and modifying a list of texts with duplicate values.

Other solutions that already exist
URL parameters/paths – Use parameters and paths to trigger your page’s current view and use the user’s browser history to keep track of those paths and parameters. This has limitations: It requires exposing URLs that you may not want the user to revisit later. To work it must fills up the history with each historical page view. Clicking back may take the user away from the page. Solution has has development overhead other limitations.

Use the database - create a db item to store user page views. Sort by date created. This solution requires a lot of overhead and may come at the expense of speed. Hard to scale with a lot of users constantly writing to the db when navigating around.

Anyways I hope this helps anyone looking for a solution with lists and multiple items.


I should also note, that this is a good codeless solution for any scenario where you might want to use a traditional javascript array This is a nice similar equivalent for the JS .pop() method.

1 Like

Storing you list as joined texts sounds like a good solution, but what if you hit the maximum amount of characters allowable for a string?

What is the max length?

For a page states, I would hazard a guess that it rides the rails of JS and JS string literals, which in theory is ‘unlimited’ (the size of memory on the user system). For the database, I assume the max length is pretty big, this is all I could find on the forums…inconclusive:

The underlying technology of the bubble db is postgres sql which, for a ‘short text’ has a 64kb size limit or 64000 characters. Also fairly big. Assuming that its not less though.

Finally, for the alternative to what I’m describing (lists), its not clear to me if they also have a similar size limit in the DB (are they stored as text in the db?) . The reason I say this is because a ‘list of things’ doesn’t really like to be more than a couple thousand items. A postgres array should have no trouble with this, however if you take the text limit of 64,000 characters and divide it by a thing’s 32-character UID you get 2000

I’m certainly not an expert on this though, I’d be curious if someone knows the limits for each.

This stuff just saved me hours of thinking and probably doing the wrong things. Thanks a million for that. However, I have found a small error, which needs to be mentioned. When you first append your history item to an empty history list, you need to add comma in front. If you don’t, regex won’t delete your first item when you navigate back, and the entire text string will be broken. As it didn’t for me, but after some debugging I realised it was always the first items that wasn’t “replaced” and I guess it was the comma.

P.S. Thanks again for such a thorough guide!!!

Hey guys ! Do you have any updates on this topic ?
More long-term/easy solution ?

In 2022, Bubble lists still do not support storing duplicate values in lists and that remains at the core of the issue.

Without a plugin, the only way to natively accomplish true LIFO stack (last in first out) in bubble is to use a single text field to store a list using delimited values and then using regex to parse and manipulate them. This, in turn, means a little complexity–silly as that may be.

Bubble now supports the dynamic expression feature :split by, which simplifies things a little bit since you no longer have to use regex to split your text into a list. Things get a still little cumbersome and tricky though because:

  • adding a new value to a blank list requires conditional logic for the first item to avoid inserting an unnecessary delimiter
  • even though it may seem possible, bubble does not have a native way to delete the last item in a list (popping). You must still use find/replace with regex on a single text delimited list to accomplish that work-around.

Sorry there isn’t better news on this. Crippled data structures are one of those quirks of bubble, unfortunately. I think a lot of this has to do with guard-railing how apps are designed and keeping things simple for devs in a no-code environment. Still, I’m not entirely sure why it is the way it is in the case of ordered lists.

Maybe their thinking was:

  • ‘how will the user know which instance of a dupe to select?’ / how would we build that in a way thats easy and code-free?
  • It could have been to prevent the developer from accidentally creating very large lists by accident with duplicate data
  • There was some kind of technical efficiency of this semi-ordered array.
  • Maybe it was an easy starting point back in 2015 and there hasn’t been enough feedback to justify the (potentially breaking) change;
1 Like

I’ve added this as a proposed solution to the duplicate items problem and I’ve centralized many of the instances of people requesting this feature, would be curious your feedback: Enable Duplicate Items in List: Please Create an `add-item` Function

It’s truly crazy this hasn’t been addressed.

What are the plugin solutions to creating a LIFO stack?