List Shifter: Reverse, Rotate, Swap and ITERATE (Loop) Over Bubble Lists | Now Part of Floppy

@keith - thanks for the response.
I guess I should add more context, I am giving the user the ability tor re-order their own list. I am using the drag and drop method developed by @soh.ju.hu and trying to supplement it with Shift Up and Shift Down buttons.

I could re-work the workflows used in that post, but your post makes sense as well.
Thanks

Now, building on the idea above, @postzilla.app, it occurs to me that one of the problems with “order” fields and the idea above is… WHAT IF I don’t want to manually reorder every damn product in my database. That seems oppressive, right?

So, instead of thinking of my “Default Product List” as a list of ALL products in a special order, instead I can consider as a “Featured Product List” (and I’d change its name to that). Now, what this list is going to represent is any product I want featured at the top of the Products list when a user hasn’t otherwise sorted or refined it (and the products in that list appear in an order of my choosing).

And now what I do is I only put Products into that list that I want to feature. So, again, with my admin page, I build a little widget that lets me put any Product into that list (it’s just like a cart, right? but it has shifting features). Here’s a really shitty example of doing that – when the FTR button is clicked, I toss that item into the “Featured Products” object’s list of products:

And now, I just take that truncated list… Dog Dogs, Canned Cat, maybe Gun Brand Cigarettes (which, truth be told, may possibly be dangerous) and save that as the Products field on my “Featured Products List”.

And now, when the user visits my store page, I populate the “products” repeating group with:

Do a Search for Featured Products :first item's Products :merged with [some search or a list shifter or whatever that has ALL products in it]

And now we see how damn clever it is that Bubble lists don’t hold duplicates… Because what happens is now my featured items are at the top of the list and my other items are in whatever order the :merge part is in. Just to prove this works, here’s a picture!:

And my featured items only appear once, in the top of the RG. Cool, right?

“Featured Items” is totally something I can get behind, BTW.

So my answer (sans the editorial) is still the correct answer, @postzilla.app. What you do is you take that ordered list (List Shifter’s Shifted List) and you save it somewhere – could be on the user, but it’s probably part of some other object. You just take that ordered list and plop it into a list field on some object. DONE! No order field required.

Drag/drop with List Shifter is something I’ve messed around with in the past, but don’t have super-good example to point you to.

Rather than using your current technique, whatever it is, what your dragging and dropping should do is trigger List Shifter’s SWAP ITEMS action – you take the dragged item’s index and swap it with the dropped item’s index. (Again, I don’t think you need a order field for this. However, what you’re trying to do is tricky-tricky-tricky and there could be gotchas I’ve not thought of, and it would take me quite a while to cook up a working example, but this is kind of the hint you need, maybe?)

@postzilla.app, I should note that what you are doing is actually the original inspiration for List Shifter. Somebody here in the forum was doing a thing that let people reorder music tracks in a playlist or similar and needed a “reverse” function (take the current list and invert it) and so I set out to just do a stupid little plugin that did Array.reverse() and spat that out to the element’s output.

But then I was like, “shit, you don’t just want that, you wanna be able to rotate the list and swap items around, etc.” and that became the first version of List Shifter.

Simultaneously, I had built workflow iteration into my Calendar Grid Pro plugin and was like, well, shoot that’s too important to only be available in a paid plugin and so added that and then hated the slowness of Bubble workflows and so added PROCESS List as a way to do purely in-page iteration over zillions of items inside of a workflow and now we have the monster that List Shifter is today. :slight_smile:

@keith I have been playing around with the plugin and so far have it working for most of what I am using it for at this point. I’ve also watched a few videos to get a better understanding and have gotten to do some iterations.

I am wondering if you think it is possible to use the process list function to calculate the distance from one point ( I use an input with data type of address to store the value of a zip code ) to all of the stores in my list. In my DB I have an address field for each store.

My main use case here is that I want to allow users to sort the search results based on distance from the zip code they enter.

So far I have been able to use the iteration function to get the distances as numbers. One issue with using the iteration function is that as the list of stores grows larger I get an error

So I started to attempt to figure a way for the process list feature to do this.

So, I have two questions basically.

  1. Do you think I could find a way to use the process list feature to calculate the distances on larger lists that the iteration function is not allowing for?

  2. Would it be possible to somehow track and correlate the distances as a list to the corresponding stores so I’d be able to sort by distance?

Hey @boston85719 - I can reply in more depth later, but note that the List Shifter error you are seeing is not an error so much as just a warning. More on this in a second.

First, you don’t need List Shifter to do what you want. Just like Bubble can map a Thing to its fields, Bubble can map lists of things Things with Geo Location fields to distances just fine.

If you have a list of geo locations, the list of distances between some point (a scalar geo location) and all of the geo locations in the list is just:

geo_locations_list :distance from some_point

Illustrated here: https://list-shifter-prod-test.bubbleapps.io/version-test/distances?debug_mode=true

Editor here.

PART 2: ABOUT LIST SHIFTER’S “did not run” WARNING

Like it says in the warning: You shot Begin Iterate at your List Shifter before it’s initialized. This isn’t a big deal (List Shifter just silently fails except for this message), but it’s to inform you as the programmer that you did this. (So, if you were expecting an iteration to begin and you see that it doesn’t, now you know why.)

The warning doesn’t really have anything to do with iterating over large lists and it’s possible you were probably just not noticing it before you started messing more with the Iterate feature.

However, depending on how List Shifter is configured (and the speed of the machine on which it’s running and yadda, yadda, yadda), it’s common for List Shifter to not be ready to go on events like “page is loaded” which is what causes this warning… read on for how to fix…

Additionally, as the warning notes: You can use the Initialized/Updated event and/or List Shifter’s Initialized state to run your desired Iteration when List Shifter is truly ready to go.

The main source for this warning is if you do something like “When Page is Loaded” > Workflow: Fire some List Shifter Action. In many/most/all cases, List Shifter is not initialized by the time that Action is requested. So what you do is, instead of firing an action at List Shifter on page load, you fire the action in response to the List Shifter Initialized/Updated trigger instead.

@boston85719, continuing on with that example… What are some ways we might use List Shifter in this context? Well, what if we want to compute the distance between the locations in some other units besides miles or kilometers?

We can’t just take our list of miles and do a conversion operation on each value in the list. (This is stupid, but there you go.) So, we can use List Shifter to run that conversion. I added the following to the little demo page… A demonstration of how to convert those mile values to a MUCH MORE USEFUL unit of measure – LIGHT SECONDS! (:stuck_out_tongue_winking_eye:):

First, I shoved the “distance in miles” expression into the pink List Shifter:

And then set its Process Output type to number as well:

Now I can use PROCESS List to convert the list of miles to a list. How we do that is, any time this List Shifter is Initialized or Updated, run the conversion and shove those values into its Processed List output:

And then I reference that LS’s Processed List, anywhere I want, like here:

Another thing that’s kind of fun to do is you can use List Shifter to operate on scalar (non-list) values. And I can also just drop a List Shifter into the cell of a repeating group and use it like a little computer in there, if I don’t care about extracting the value, but instead just want to show it.

So look at the little green List Shifter here:

We can use the Use Scalar field to drop a single-item expression into the element. That expression gets evaluated (any time the expression changes!) and pushed to List Shifter’s Scalar output.

In this case, instead of running PROCESS List (which I could have done), I use List Shifter’s “Set Custom Value” action to take the scalar and divide it by the conversion factor I need, shoving that result into List Shifter’s Custom Value and then publishing the value (so it appears at the output – there’s a reason for this feature that I’m not going to go into at the moment, but let it suffice to say that you can manipulate Custom Value inside of List Shifter – getting and setting its value without having to expose it at the output until you’re ready). But in this case we’re just gonna divide the miles by the conversion factor and shove it immediately to the output:

And now, of course, I can just reference that value in my RG’s cell:

Cool, right? :wink:

Yes, very cool. Thank you for taking the time to explain this. Always helpful and appreciated. I still have a lot more to learn about list shifter and excited to find out more about how I can utilize it.

By the way, I figured out how to sort by distance…was much easier than I had anticipated.

When I set the custom state list to a list of items and then clear it after, the list doesnt clear. I set the list to 50 items and the user is shown the next group but if the user goes back to the previous step (where the list is set) i want to clear the list so they start over. so i set the same custom list to empty without reloading the page (in the workflow step by step the custom list shows empty) but the custom list doesnt empty instead it stays at 50 items. (i verify this by inspecting the listshifter element custom list) am i doing something incorrectly?

is this an issue with caching?

Are you talking about a Bubble custom state? or are you talking about List Shifter’s “Custom List” output?

List Shifter’s “Custom List” output

@3brotherssupply: Just checked and, yeah, it seems that setting List Shifter’s Custom List to null/empty does not actually clear the list. (This would be a bug as the docs do say that you can clear it by setting to null. Will fix in a near future update.)

FYI, just pushed List Shifter version 1.9.8, a bugfix release that that fixes the SET Custom List action. (Previously, setting the Custom List state to a null/empty value did not actually clear the list, as stated in the documentation. Now it does.)

When you do SET Custom List and leave the value field empty, the result is now a zero-length list. (Don’t forget that you must PUBLISH the Custom List value for it to appear at the output.)

BTW, the Custom Value and Custom List states are very useful for applications where you are using List Shifter as an alternative to custom states. (In fact, they are designed in part as replacements for custom states that you might put on some object in the page, and work very much like custom states.)

Here’s a quick rundown of the types of things held in List Shifter and how they are different:

  • List to Shift: A list of items of type selected in Data Type of List. This list is echoed to List Shifter’s “Original List” output. This list is also echoed to List Shifter’s “Shifted List” output, in potentially modified form (via the Reverse, Rotate, Swap, Sort, etc. actions). Whenever the value of the List to Shift field changes, these lists magically update.

  • Use Scalar: A single item (a scalar value) of the type selected in Data Type of List. This value is echoed to List Shifter’s “Scalar” output. Whenever the value of the “Use Scalar” field changes, this value magically changes.

  • Custom List: A list of items of the data type selected in the PROCESS Output Type dropdown. This value of this list is set by the SET Custom List action and can only be changed by executing the SET Custom List action again. The list is held internally in List Shifter where it can be accessed in the PROCESS List action. This list is NOT automatically exposed at List Shifter’s outputs. It is only echoed to List Shifter’s “Custom List” output in response to the PUBLISH action or if the “publish” option is set in SET Custom List or PROCESS List actions.

  • Custom Value: A single item (a scalar value) of the data type selected in the PROCESS Output Type pulldown. This value is set by the SET Custom Value action and can only be changed by executing the SET Custom Value action again. The value is held internally in List Shifter where it can be accessed in the PROCESS List action. This value is NOT automatically exposed at List Shifter’s outputs. It is only echoed to List Shifter’s “Custom Value” output in response to the PUBLISH action or if the “publish” option is set in SET Custom Value or PROCESS List actions.

  • Processed List: A list of items of the data type selected in the PROCESS Output Type dropdown. The values in this list can only be created or set via the PROCESS List action, though an existing Processed List can be cleared via the CLEAR Action. The values stored in Processed List are automatically published to List Shifter’s “Processed List” output when the PROCESS List action completes.

  • Processed Result: A single item (a scalar value) of the data type selected in the PROCESS Output Type dropdown. This value can only be created or set via the PROCESS List action, though an existing Processed Result can be cleared via the CLEAR Action. The value stored in Processed Result is automatically published to List Shifter’s “Processed List” output when the PROCESS List action completes.

I’m sure you can think of many clever uses for these values, beyond the examples I’ve shared in previous videos about List Shifter! :wink:

Just a note that List Shifter is now at version 1.9.11. Version 1.9.11 is a bug fix release that fixes an issue with the GET INDEX Action.

Detail: In early versions of List Shifter, the GET INDEX Action worked on any type of list – whether the list is of primitive data types or Things. However, in later versions of List Shifter, changes that I made to how lists of Things are read and stored caused GET INDEX to not work properly for lists of Things. Version 1.9.11 corrects the issue and you can once again use GET INDEX on any type of list.

@keith Is it possible to place multiple BEGIN Iterate actions in a workflow? When I am testing, does not seem like they work properly. I am doing a “Make a new thing” for each from the Original list, it seems like they both only partially complete.
Wondering if it only needs to be 1 iteration action per workflow.
Thanks

@hero: A couple of things:

  • There can only be one active Iteration going on per List Shifter at any given time. If you hit a List Shifter with multiple BEGIN Iterate actions, you’ll see a message in the debugger and/or your browser console. If List Shifter is iterating, it will not start another iteration and the message tells you this.

  • If you build a “When Iterate” workflow that includes data operations, ESPECIALLY “Make a New Thing”, note that you will run into something that you’ve probably never seen before. What you will find is that your page thinks that the object has been created almost instantaneously – and in fact it has – but it only exists in the page. Bubble basically caches those pending creates. If you try to leave the page, Bubble will warn you that it is not safe.

You can watch this happen. In another window, open the Data tab of your app and look at App Data for the data type you are creating. As you refresh the page, you will see your database updating. You will note that it takes MUCH longer for the object to actually appear in your database than it would seem from how your page behaves.

This is a long way of saying: Just because List Shifter can help you fire off a large number of data operations sequentially, that does not mean that your app is any faster on the back end.

How many items are you trying to create?

@keith
Thanks for the response, I try it in a couple steps.
The number of items will vary based on the user input, but i think max ~500.

Just know that it can take a VERY long time to create 500 new items. What you’re trying to do here is possible with List Shifter, but is not necessarily a good idea. Just FYI.

BTW, if you’ve not watched my video that gives a recap on how to use the Iterate action, you should watch that it (it’s the one in this reply, up the thread):

@keith
Yes - just getting into your videos, I am basically trying to bypass bubble’s limitation on Copy Lists by using Iteration, I am going to try Process instead.