Forum Academy Marketplace Showcase Pricing Features

List Shifter: Reverse, Rotate, Swap and ITERATE (Loop) Over Bubble Lists | Now at v1.4: Adds Numeric Option, GET INDEX Action

Hi again @keith ,
I just wanted to report a possible bug I’m experiencing:
I have a list of texts that I have in a RG and which I want to allow the user to reorder. This is easy enough with your plug in of course - I have an up and a down arrow which trigger “Shift up” and “Shift down” events.

The tricky part is that I want the reordered list to appear simultaneously in a ‘preview’ pane on the page, and I can’t pull the LiftShifter list directly. As such, what I’ve done is have the preview pane pull data from my original data ‘thing’, and then I simply update the thing after each ‘shift up/down’ events, setting the relevant list to the ListShifter shifted list.

Now what’s weird is that this works half the time - specifically, it works on almost all odd numbered clicks of the arrows. On even clicks, the list shifts and the thing is modified (as reflected in the preview pane), but then it spontaneously undoes itself. So for example, if my list is [a,b,c,d], and I click to move ‘b’ up, I’ll get [b,a,c,d], as expected, but if I then try to move ‘a’ back to the top of the list, I’ll see it change to [a,b,c,d] for a second (in both the RG and the preview) and then suddenly revert to [b,a,c,d]. (Similarly, if I try to move ‘d’ up, for example, I’ll see [b,a,d,c] for a second and then it will revert to [b,a,c,d].) Again ths seems to happen on even numbered clicks - after this happens I can successfully move ‘a’ to the top of the list and have it ‘stick’, but then the next click will exhibit the save reverting behavior

Maybe this isn’t a bug but a mistake I made somewhere, but the workflow is so simple (Shift up/down followed up a simple ‘make a change to a thing’), that I don’t know what I could have done wrong. (And becuase this happens regardless of whether I’m trying to shift items that I had previously shifter, it doesn’t seem like the list isn’t getting updated somewhere.)

Do you have any thoughts?

Thanks!

Slight update: I discovered something a bit strange: If I use the Bubble debugger set on ‘Slow’ or ‘Step by step’, the problem doesn’t occur. However, it still occurs when the debugger is set to ‘Normal’, no matter how much time I wait between clicks.

Update 2: It seems to be a simple problem with updating lists upon reordering? I’ve reproduced the problem here:
Re-ordering list test

Hi @keith
I found an issue in a debug.

When user click a button, a popup appears, and I set “one popup is open” as a trigger of “BEGIN ITERATE action”.

As you can see in the attempted movie below, the iteration isn’t initiated.
https://drive.google.com/file/d/19I1IQd5ZMor1gC6_z9cyKliv1UePZtJP/view?usp=sharing

Do you know how to solve it?

Hi Keith,

I really like where you are going with ListShifter because it addresses the biggest gaps in Bubble. I have bought you a round of drinks based on what I have seen and to ensure my future Karma but am hoping you can explain some funky behaviour I am seeing when I try to use the Iterate function.

I built a page that basically replicates the simple math example you built in your demo but it failed to get past the first iteration on both Chrome and Firefox. I assumed that it was my error but ended up trying to run same page from a Linux computer and it worked like a charm… at first at least… on both browsers. After I retried several times, it the console started spitting out warnings about cross site cookies. Eventually it stopped working consistently on one browser. In the interim, I tried it on another windows machine and it worked fine. In the process of digging into things on the console on the original computer, it eventually started to work in Chrome but the problem persisted in Firefox. Very strange. In the end i tried it on two Windows and one Linux boxes each with Chrome and Firefox. My conclusion is that whatever is causing it is neither Browser or Operating specific leaving only my home network as a cause … and I just tried it using my celular network and the problem persists.

Based on other recent posts, it sounds like I might not be the only one finding these errors so you are probably on top of this already. However, if you are interested, I can send you some videos taken from the various machines - I would prefer not to share these on an open forum as I don’t want to take the time to erase all personal identifiers. Let me know if you are interested.

I have come across what I think is a different anomoly, which be the same problem but may also be a quirk that you may not of anticipated and is more akin to a feature than a bug, A developer working on my app, built a routine that I thought I had replicated perfectly on a different page but kept getting different results - some of them completely whacky. I finally noticed that I had sorted the Repeating Group differently on the two instances. Is it fair to assume that ListShifter is not built to deal with sorted Repeating Groups?

The routine is built so that the repeating group was inside another repeating group and ListShifter is inside the first repeating group.

And on a final note,… what the heck are you making this free for? I might be off base here but it strikes me that this plugin is far too complex to be a low maintenance widget that you can keep up to date in your spare time for the occasional karma coffee or pack of smokes. And it is way to valuable to the entire Bubble community, for it make sense for any of us to want to see you give up on it because it becomes too much effort.

2 Likes

Hey @kevin.hunt, thanks for your kind comments and ALSO for your generous contribution to the development of Bubble plugins that do not suck! :slight_smile:

As for the problem you are describing, it’s impossible for me to say what’s going on in your Iterate workflow without actually seeing it. If you can put your simple example into a project where anyone can edit (DM me the link), I can take a look sometime soon-ish.

There is probably NOT a problem with List Shifter, but more of a problem on your end understanding what, exactly, is happening. Though it’s possible something is wacky in Bubble that impacts what it is you’re trying to do. (I see no problems with List Shifter ATM, BTW, and I use it all the time.)

Aside: For simple mathematical operations, using Iterate is a waste of resources. Use the PROCESS List action. See the video way up above introducing PROCESS List. It’s much faster for simple math stuff (native JavaScript speed). The only reason to use Iterate is if you need to ping the database to fetch some value or something within each workflow iteration.

As for your List Shifter-in-a-repeating-group scenario, any wacky results you are most likely the result of misunderstanding “what happens when” in Bubble. While you can do this (put a List Shifter into a repeating group, resulting in a bunch of List Shifters (one for each cell) all doing their own thing (s) within the scope of that RG), this is NOT what List Shifter is for.

List Shifter is (in part) a way to compute values before sending them to a repeating group for display. (Repeating Groups are stupid and cause Bubble developers to be confused about the difference between computing values and displaying them.)

Basically, if you have a List Shifter in a Repeating Group cell (meaning that you are, at runtime, creating a bunch of List Shifters, each of which exists in a cell of that RG) and are then firing off “Iterate” actions, that’s gonna get real wacky real fast. Because each List Shifter will be firing off workflows iteratively at the same time.

I can’t think of ANY practical use case for doing that. (Such List Shifters [probably just 1 List Shifter] should exist outside of the RG, compute what it is that you want to display, and then use the outputs of that List Shifter in the RG.)

Anyway, I’d be interested to see what it is that you are trying to do. The solution is likely rather simpler than how you are attempting to do it (whatever “it” is).

As for why List Shifter is donation-ware, rather than a commercial plugin: List Shifter started as just a (nearly) one-liner to do .reverse() an an array of values in a List of primitive data types. (That function, amongst many others, being mysteriously absent from Bubble.) But of course, I couldn’t stop there.

If you want to reverse a list, you might also want to change the positions of items in the list (“SWAP Items” action). Or you might want to rotate (“shift”) such an array (hence the name, “List Shifter”). And, it’s really common design pattern in Bubble to store a “selected item” (in a custom state) so that you can do something special with it. (Why not build that into the plugin as well, and save a lot of time?)

And then, people asked for List Shifter to work better with Things, and that’s an interesting subject to explore in Bubble plugins, so I added that.

A little earlier, I had completed Calendar Grid Pro, which incorporates similar “Iterate” functionality that I later added to List Shifter. (In CG Pro, it can be used to iterate over internal lists of dates that that plugin generates and that was developed to solve a specific problem that I needed to solve for myself for my own commercial Bubble-built app.)

Obviously, it would be useful to be able to iterate over any sort of list and it was kind of a no-brainer to make such a feature available in List Shifter. And I did think about making that “List Shifter Pro” (a paid plugin). However, there were other considerations:

  1. At the time, this feature seemed too useful to just be limited to folks with paid plans (only paid apps can use paid plugins).

  2. It pisses me off that Bubble doesn’t easily enable arbitrary, client-side iteration and forces people to do dumb stuff with backend workflows to accomplish very simple looping operations, and I just wanted to make a point. (The point being, “c’mon Bubble, your users aren’t as stupid as you think they are, please finish the product.”) Bubble is a half-finished, array-oriented language. Somebody has to point this out, might as well be me.

  3. While the Iterate feature was very novel and kind of breakthrough in terms of my own plugin development, it’s not actually hard and a really skilled JS developer would immediately see that this is possible just from reading the docs in the plugin builder. (I even posted about the pre-“a-ha!” moment, in this post.)

  4. In fact, there’s another plugin dev who realized the same thing at almost exactly the same time that I did. (They just didn’t understand how useful and important that was and implemented it in a paid plugin in a different way.)

  5. There’s also a bunch of not-very-good Bubble plugin devs who would likely stumble upon the same idea and either (1) develop crappy versions of it or (2) outright steal it from commercial plugins without really understanding how it works and take people’s money for it, but do a shitty job of the whole thing.

So, I just built it into List Shifter and made it free, but also well-implemented and fairly-well supported (while List Shifter is fairly mature and updates are sporadic, it’s something that I constantly improve).

This turns out to have been the right decision as “Iterate” isn’t really all of that useful because of how slow workflows are (for reasons I will not belabor here). Most of what Bubble devs want to do is better served by the PROCESS List action (which is itself very innovative) and better makes my point about Bubble being a half-assed / half-finished array-oriented language.

As more and more people use List Shifter, I see what they are trying to accomplish and try to make things incrementally easier. One big thing people seem to have an issue with is how to count some things in an array-wise manner (even though this is trivial using PROCESS List), and so the next update to List Shifter features a built in “count the number of things in a Thing” feature that hopefully will alleviate such pains.

Also, there is a server-side version of PROCESS List that I’ll release soon-ish (as a paid plugin, because it’s more specialized). But first, I need to get my next paid plugin “Cheap Date Tricks” out, which I hope to finally release this week (it solves bunch of common date/date range/date list/date range list problems that people often run into).

1 Like

Hey @keith ,

Thank you for the response.

1.) The Bubble Debugger was causing my issues with Liftshifter
Gaby at CoachingNoCodeApps, figured out that my issues with my little test version of ListShifter were ALL caused by running the app in Debug Mode. There were some other totally unrelated issues that came up at the same time that she also helped disentangle!

Side note - To all those reading this note, who are thinking about trying out Bubble, I can say that my decision to invest in the service that Kristen and Gaby have developed was one of the best I have ever made - they are without a doubt the best combo of training and coaching that I have ever seen. Gaby knows all of Bubble’s quirks and gives great advice on how to build apps that will not just work, but work efficiently.

2.) Re. putting Liftshifter into a Repeating Group -
I had come to suspect that putting a Liftshifter into a Repeating Group might confuse Bubble. I will try to figure out how to do this better on my own with Processor before bothering you. I don’t want to slow down your work on your new Cheap Date Tricks plugin!!!

3.) Re. your decision to Open Source LiftShifter
It is clear that your passion for doing good for the community will ensure the continued development of the amazingly valuable apps you are building whether they are paid or not.

4.) Will Cheap Date Tricks work with Time lists
I am trying to build a week calendar and finding it horribly slow - are you going to include the Time stuff that you have been talking about, in this new app?

Cheers,

Kevin

Hi @KeitaroNakata ,
I think that I might have been experiencing the same as you. Thanks to some help from Gaby Romano, I was able to determine that my issues only occured when running the app in Debug Mode. You may want to check whether this works fo ryou as well.
Cheers,
'KH

1 Like

Hi @michael.dascal,
I had some inconsistent results that turned out to be caused by running the app in Debug Mode. You may want to see if the same is the case for you.
Cheers,
Kevin

Hi @Keith , hello everyone,

first of all, thanks a lot for your plugin. It is REALLY useful. I’ll definitely offer you a pack of smokes soon (need to refill my debit card to pay).

I have been using and studying your plugin a lot during the last few weeks, and I managed to achieve my goals thanks to it. I thought it would be nice to share what I am doing with it, as I think it’s a nice and useful way your plugin can be used for.

I’ll explain you my setup:
I have books, ads and users. Starting from a list of books, I want to show a “best combination” of users that have ads for these books. The goal is to find an ad per book minimising the number of users.
This is the idea:
Suppose we start with 6 books. First step is to identify which user has more ads for these books. We then select these ads, save them somewhere, and ‘remove’ the related books from the list. In this case A is selling four books: I save its ads, remove these books from the list and proceed to the next step. Now we only have 2 books left and D is the user who is selling most (2 out of 2). We then select these two ads, add them to the list where the 4 ads of A were and remove the two books from the list. Now the list of books is empty so the process is finished.

This is how I did it with your plugin:

  1. ListShifter A - I search for all the ads for the books that are in the list, and take the users from there.
  2. ListShifter B - Takes the unique ids of the users
  3. ListShifter C - Takes the unique elements of list shifter A

These are then the three workflows needed:

  1. Set process field and set list, count occurrences for every user [EDIT: Here it should be ListShifter A to be triggered… does not change that much anyway]
  2. Sort list
  3. Firstly, add the ads of the first item user (the user who is selling more books) to a list of ads. Secondly, remove the books for which an ad is found from the initial list of books. Note that this is exactly the source list for the ListShifter A, so it’s updated and the first workflow just start again immediately with the updated list.

After all of this…
I think it’s very interesting and it really does what I wanted to do but… it’s very slow if the number of ads and users is a bit big (I mean like 20 books, ~400 ads and ~200 users. [I mean only the ads and users related to the 20 books, then there are much more ads and users in the db not related to the search]). And with slow I mean like 20/30 seconds to do everything.
The slow process seems to be the first workflow, when I do the ‘Do a search for’ in the ListShifter A.
As I do not really understand what this plugin is really doing behind the scenes, I wanted to ask you if you have any advice or suggestion to speed up this process.
One thing I noticed is that if I go to the previous page and then come back to it, it goes super fast. It does all the iterations again but in less than a second. I tell this to you because maybe it helps to understand where the slow process really is.

Thanks again for your contribution and sorry for the very long post, but I really hope you can help me with this!

Best,
Carlo

EDIT:

I add here one example of how long it takes…
The two timer laps are one at the end of the 1st workflow (init) and one at the end of the last workflow (states.)

Starting from ~300 ads of ~150 users…
I tried to use a boost but nothing big changes even if the debugger sometimes tells me I can save few seconds with more capacity… I tried to keep every search server side but maybe there’s something I’m missing!

EDIT 2:
I tried to add some more timers and apparently the long lap is between the end of the last workflow and the beginning of the first one. So, let’s say, it takes a long long time for ‘ListShifter Initialized/Updated’ to be triggered. I understand that is 99% something that has nothing to do with your plugin but I really hope that with your understanding of what is going on behind the scenes you’ll be able to suggest me a magic trick to speed up this process.
Also, I still really can’t explain myself how can it be so fast when I do it for the second time going back and forth between pages.

EDIT 3:
Maybe using custom events the trigger can be faster?

Thanks again!

HI @keith
Thank you for fantastic plugin.
Now I am facing an error which happens when I fire BEGEN ITERATION ACTION when page is loaded.
The error message is below.
How can I triger when it the page is loaded?

I found that When I test it with Step by Step debug mode, it works fine.

Sorry and one more.

I found that When I set two iterate BEGIN trigger, they finished unexpected count.

Iteration A should be iterated 3 items(step 2) and Iteration area should be iterated 4 items(Step 3), but they finishes only 2 count.

Another issue happens when I Loop in Loop action.
in general with coding, like the FOR for statement in the FOR statement.

Hi Kevin,
Thanks for point this out! I think I had tested it outside of debug mode in hopes that this was causing issues, but it didn’t seem to change anything.
In the end I developed a temporary workaround, but perhaps I’ll go back and see whether this contributed.

Thanks again!
Mike

You can’t nest loops like this with List Shifter. In your example picture, Step 2 and Step 3 will fire at basically the same time. The looping is not synchronous. It is asynchronous. (That is, Step 3 will not wait for the the iteration fired off in Step 2 to complete.)

You can do fancy looping things with List Shifter’s PROCESS List action, but that action IS synchronous. You can’t go and read things from the database in between iterations. You must pass all of the values you wish to process into the action, via the “constant” fields.

Basically, what you’re trying to do with List Shifter’s Iterate action will not work the way that you have it set up. You could possibly make it work, but not in a single workflow like this.

You have to do Step 2 (as its own workflow) and then WAIT for its iteration to finish. (You detect that it is finished by listening for the Iteration Complete message.) Once you receive that message, you can do the iteration kicked off by Step 3. You have to structure your workflows very differently from how you are doing them now.

1 Like

Slightly off-topic dept.: List Shifter fans will likely be interested in my new (paid) plugin Parallels, a plugin for date/date list/date range/range list manipulation. Bubble is still “reviewing” the plugin, but it will be available soon. Official thread here:

1 Like

Hi:

Is it possible to shift items up and down from different pages when List Shifter is in Pagination mode?

I’ve tried multiple ways - I know it is by design based on Keith’s video and I’ve also tried to use 2 list shifters at the same time, but no dice.

Anybody come up against the same use case?

Well, this is just really tricky to do as it’s not supported by List Shifter. The reason being that List Shifter (in general) does not know, nor does it care, the VALUES of the items in your list. This is part of the magic.

Consider the following:

Q: What do I need to know to swap two items in an array? Do I need to know their values?

A: No, I do not need to know their values. I need only know that you want to take item X in the list and swap its position with item Y in the list. And this is what SWAP does.

When LS is in Pagination mode, there is (at present) no concept of X’s position in the full list versus where it is in the currently displayed page.

It’s not impossible to know this, it’s just something that List Shifter doesn’t handle right now.

Hi Keith:

I really love your plugin and the expertise and elan with which you put it together. I really appreciate it. I’m trying to get an MVP up and monetize and am definitely wanting to buy you a cup of coffee or round of drinks. (FYI, if you have a Paypal account, I’d love that as it is waaaay easier.)

I figured that my ask wasn’t something easy to put together due to the logic under which List Shifter and bubble pagination operates. I’ve tried a couple hacks and have tried to work around it but - it’s not entirely clear what workaround that would be.

I’m creating a document builder and users may need to move part of the text up or down as they edit and create the document. This is my main problem right now and this is what prompted me to write to the group.

Later on, I’ll need to group items together and then process and save them to a new list - but I figure I can do this with some of your posts about featuring the process function. If I understand the logic properly, this should work.

Would you point me in the right direction? I’m not sure where I should investigate at the moment for moving some items from one page of List Shifter to another. (Or perhaps I could use 2 Listshifters and then sort on an item tagged with an incremental number, then make changes to the number when it is shifted up or down. I’m not sure, will have to think on it.)

P. S. I know you must be very busy. I know it took time to learn what you know and you are very generous to share it with the community. I understand this and I appreciate it. Regardless of any reply, I appreciate your making this plugin karmaware so that entrepreneurs like me can figure out how to use it and if we have an MVP. Hopefully I can monetize and do more than just a cup of coffee or round of drinks; I see the love and care you put into this project and I recognize it. Thank you for your commitment to community and your passion for quality.

Hello @keith
I asking myself how to sort a rg by a first criteria then a second one with the plugin ?
I need to filter first by emergency (yes/no) then by priority (number).
Hope you can help

Hi @keith and thank you for this amazing plugin,
Hi @ListShifterlovers,

After a few days trying (and failing) to store the results printed in a repeating group (see link below), some skilled bubblers pointed me to your direction.

To make a long story short, i want to print a graph (and for that I need a list) with data calculated and printed within a repeating group. Not possible to make that list outside the RG as the data is a running balance, each amount being linked with the previous row of the RG.

Would it be possible to hack this problem with one of the so many List Shifter’s features?

Thank you so much,
Romain

Hi @keith and thanks for your contribution.
Is there any way I could use List Shifter to sort a RG by a text element (Distance) which value does not come from the database.

I’d like to sort the RG by distance. The distance does not come from the database but from an expression placed in the RG cell.

Yes, you’d use the PROCESS List action to build your list of running balances. See my introductory video to Process List.