FLOPPY: Plugin for localStorage, sessionStorage, IndexedDB storage, List Creation/Manipulation, Iteration, and More! Now with even more video docs!

Hi Keith and the rest of the world, I found this plugin recently and it seems like it will be good for my case, but I need a little wind at my back.
I’m building an app that uses Xano as a backend and I’m utilizing state for the rest of the time.

We have a layout shown below that should have support for Drag n Drop functionality.
I’m utilizing state and instead of having some array of items (bubble list issue), I have separate states for:

colleague_1_full_name
colleague_1_bio
colleague_2_full_name
colleague_2_bio

I’m unable to use List since we can have two “John Doe” and Bubble removes duplicates from the list.
Floppy to the rescue!
It would be a lot easier to have an array with objects (data I’m retrieving from Xano API):

[{ firstName: “string”, bio: “string” }, { firstName: “string”, bio: “string”}]…

My Floppy instance has a Type of Value “Student” that looks like the object above, but when I need to click on the button “Add Colleague” I would need to push the same object to have those keys for text update (bio, full name, etc). Using Arbitrary text was not very helpful so I made one API call that will return me Empty Student and with that, I’m able to push that one to the floppy.

The Issue I have now is when I want to update student[1].bio. for example.
While I’m writing this now, it occurs to me that I should use the Change RAM List Value(s) a Floppy > Change Single Value, and filter function to first find the item I want to change and then update only the desired key?
Sorry for the wall of text and thanks in advance!

Hey @saybubble - so, if I understand your question properly, there are a few things that you might already be aware of (since you’re working with an external database) but that I want to make very clear:

  1. The only type of objects that Bubble supports are Things (custom data types defined in your database), API response objects (for lack of a better term - these are Thing-like from a Bubble plugin API perspective, but do not have a “unique_id” field), and Option Sets (which aren’t really relevant here).

  2. Bubble does not support arbitrary JavaScript objects. (Though, of course, if you have a text or a list of text, those strings could be formatted like JSON and so could represent JavaScript objects but Bubble cannot understand them as objects.)

  3. The only real “objects” that we have in Bubble are Things and Things only exist in relation to the database. That is, there is no “in page” representation of a Thing, we cannot create a “temporary” Thing that only exists in the page, and plugins cannot create or modify a Thing. The only way that a Thing can be created is via the native “Create/Change/Delete a Thing” Actions. (To create a new Thing, we use Create a New Thing action. To modify a field on an existing Thing, we use Make Changes to a Thing, etc.)

  4. To be very clear about point 3: In the Bubble plugin API, there is no facility for creating a Thing, destroying a Thing, or modifying the values of the values of the fields (keys) on a Thing. In JavaScript terms, Things are objects with some methods on them. But these methods only allow us to do two operations: (1) Understand what fields are on a Thing and (2) get the values of the fields. We cannot set or modify those fields. This can only be done under the Bubble programmer user via the native Create/Change/Delete actions.

  5. As I mentioned, API response objects are Thing-like. They can only be created by the API connector. And, worse than the case with Things, there is no facility to modify any of the fields on an API response object (neither plugins nor Bubble programmers can do this at all). All API response objects are unique and just like with Things, all a plugin can do is understand what fields they have and what the values of a given object’s fields are.

So, given all of the above, don’t be confused about what Floppy’s RAM List is and what Floppy’s various RAM List-related Actions (like Change RAM List Value(s)) do:

  • Floppy’s RAM List is a Bubble List (Bubble’s version of an array).
  • As with all Bubble Lists, Floppy’s RAM List has a type and can only hold values of that type.
  • We can put new values of that type into the list, remove them from the list, reorder them in the list, etc.
  • We can “change” an item in the list, but this does not mean “Make Changes to a Thing” (this can only be done via the native Bubble action) or “Change some field on an API response object” (there is no way to do that at all in Bubble). What “Change RAM List Value(s)” means is “replace some value with some other value”.

To be very, very clear about this, let’s say that you’ve set your Floppy to be of some Thing or Thing-like type. In this example let’s say it’s the native User type. Things (including Users) are referred to by their unique IDs but for the sake of simplicity, let’s just refer to them by their first names. I could use Floppy’s RAM List to hold a list of Users, let’s say I have:

[dick, jane, keith]

Now, I can do things like Swap dick and jane to get:

[jane, dick, keith]

And I could change the User held where dick currently is, by using Change RAM List Value, to User john to get:

[jane, john, keith]

What “Change” means in this context is “replace this item with some other item”. It does not mean that you can “make changes to some field on the Thiing in the list”. Let’s say you wanted to take that list of Users and update some field on all of them. You could use the Bubble native action “Make Changes to a List of Things” with Floppy’s RAM List as the argument and (for example) change the value of some field on all of them. But you can’t do this in Floppy itself.

I think you probably understood all of that already, but if not, now you do.

Again, though it is stupidly limiting, there is unfortunately no way to have a generic object in a Bubble list. Generic JavaScript objects cannot be sent to Bubble plugins nor output by Bubble plugins as there is simply no such thing in Bubble and Bubble is strongly typed.

So, you’re essentially approaching this the right way. You can treat everything as strings (texts) and have two parallel lists (a list of full names and a list of bios) or you can just turn everything into strings (concatenate the name and bio data into literal JSON format or JSON-like) and do string manipulation on the values.

But then of course, you presumably want to communicate that back to Xano. So, presumably you need to have a call to Xano that can accept the list of names and list of bios and create new Xano objects from that.

But from what you describe:

… note that the “Empty Student” object (an API response object) cannot be changed inside of Bubble in any meaningful way.

Now, there are ways of abusing the API connector to do Thing-like in-page operations (that is, manipulate objects), but this involves communicating with the API connector to change an object. And, in this case what you’re doing is not actually changing the object, but getting a new object back from the API connector that has your desired field values set. This is the sort of thing that @jared.gibb is into and I assume that’s the sort of thing you’re doing here.

I don’t use Xano, so I can’t advise much further, but assuming you can make a new API call that can make a new Student with some field(s) set, just do that. And what you’re holding/managing in the page is text strings, not objects.

As I belabored above, you can’t create a new API response object by any means other than interacting with the API connector. Nor can you change an API response object that you get back from the API connector.

But you could collect the field values and then use the API connector to create an object back in your remote database that has those values. Or you might have an API call that - given the desired field values as arguments - changes the database object in question in your backend database.

4 Likes

Hey Keith, you deserved some karma-coffee that’s gonna be on the way, warm :slight_smile:
Thanks so much for explaining this to me in detail.
I knew things from 1-5 but not in such detail, some clouds are out of my way now.

It’s a bit unfortunate how this works, I know it’s made for people without or with limited tech skills, but for me who has been in Frontend development for around a decade this is a bit, let’s call it strange.

I can structure my database differently. I thought about having two arrays, for names and their bios:

[dick, jane, keith]
[dick bio, jane bio, keith bio]

Because I know Index from repeating group I could update those easily but the issue I encountered was because I added two Floppy Instances on the page. One for names, the second for bios, and the issue was when I tried drag-and-drop.
I wasn’t sure how to make an update to one repeating group to reflect on another group’s data.
I hope you can understand the approach I tried there.

Note that the “Empty Student” object (an API response object) cannot be changed inside of Bubble in any meaningful way.

I learned that the hard way. :slight_smile:

And what you’re holding/managing in the page is text strings, not objects.

I will have to try this way, it is my last resort.
Where’s that Karma-Ware link? Next coffee is on me.

Many thanks, I wasn’t alone :slight_smile:

1 Like

Glad I could sort of help?

1 Like

I’m testing out Floppy now and I really like this plugin. I have a question:

When I do a search and store the resulting list in local storage, I see that for each Thing I only have the ID.

Is there any way to retrieve the values for the fields and also store those locally? Either on the drive or RAM will be fine.

My issue is I have a number of user data types where the user can define a list of items, but the list is typically only about 5-20 items and once created they rarely change.

However, through the use of my app, there are many times where I need to reference the these lists to find the value of something. What I see from my server logs is that it seems to be searching the DB again each time it needs to get values from one of these Things. I’d love to just push the entire lists into the user’s comptuer (drive or RAM) and access the values that way.

Is this possible?

Thanks!


I have another question.

I have an element with a data source that is a list from the DB. This element is the source for a RG. It seems to take up to 20 seconds for this to populate on page load. (I’m working to resolve that separately…)

Is there a way to use Floppy to store the list locally so it populates quickly on page load, but is then again dynamically linked to the DB after page load? In other words, I want to populate my element quickly with a mirror of the DB, but then retain normal function after that.

What would I use as the source for the element? Do I keep the source as the DB field and then use a workflow to display the local list? Or is there some other way?

Thanks.

Hey @ken1: The only representation we have of Things is their unique IDs. So, if you use Floppy to store a Thing or a list of Things, yes, what you will see is their unique IDs. When these IDs are read by Floppy (or Floppy Reader), they are rehydrated into the actual Thing objects by Bubble and appear at Floppy’s List Value or Scalar Value output.

You don’t say what the list of 5-20 items you want to store locally is, but I’m assuming they are Things. If you want to store details about those Things locally, you would either use multiple Floppys to store those details as parallel lists of basic (non-Thing) datatypes. (Note that the somewhat mis-named “Floppy Reader” lets you manage multiple List and Scalar keys from a single element, which can be useful in this sort of application.)

Unfortunately, this is the best we can do in Bubble at the moment. There are no object datatypes in Bubble except for Things, really, and Things only exist in interaction with the database and there is no “in page” version of a Thing.

Additionally, plugins cannot have dynamically typed outputs. The Bubble programmer always has to specify the type of the output that will be used. Additionally annoying, plugins can’t dynamically create new outputs so we must always pre-define how many of some output we need.

The combination of these three issues precludes me from building a nicer interface to Floppy that would allow for the automatic configuration of multiple outputs (even an arbitrary number of outputs) to make this easier. (Or, more sensibly, provide an “in-page” version of a Thing that acts like a Thing but does not require interaction with the database.)

But as I say you can decompose the Things you want to store locally into their component parts. For example let’s say your list of items is a Thing called a Contact that has two text fields on it called Name and Phone Number.

Well, you could configure two Floppys (or a single Floppy Reader which would be my preference) to manage two browser storage keys located in localStorage or IndexedDB storage (which would be my preference). And then you’d shove the Name and Phone Number lists into those keys.

Here’s one way you could configure a Floppy Reader for this type of use case. Configure it to use IndexedDB:


Define 2 text list type keys for Names and Phone Numbers:

Define the Database and Datastore to use:

And then you can put values into those list keys using the Store Keys FloppyReader action:


You would then use whatever expression resolves to the list of Names and Phone numbers for Value for List Key 1 and Value for List Key 2, respectively. (e.g., Current User's Contact List each item's Name or whatever.)

And then List Key 1’s output (list of Names) will correspond to List Key 2’s output (list of Phone Numbers). So Contact #1 is Name #1 and Phone Number #1, etc.

Again, this is stupid and huge limitation of Bubble but it is what it is.

As for question #2, you certainly can do that. (Try it.) But as to whether it’s faster or not depends on the use case. Basically, when Floppy (or Floppy Reader) is initialized, you set the RG’s source to be whatever list output represents your list (if the list isn’t empty).

In the same way that you say you have an element that has a data source, or that you could have a custom state that holds some data source, the Floppy, Floppy Reader, Floppy Expression Watcher and List Shifter are all also things that can hold a reference to some scalar or list value(s). They are generally more useful than Bubble’s built-in facilities for such things as they do things like notify you when they become initialized.

Currently I’m loading 8000+ records to a state (at startup), This is to avoid bubble WU consumption for every search i make. terminology is simple - When user is logged in all data (for users to search example cities or products) will be loaded to a state and all search will be on client side using :filter. My App is super slow in browsers, will Floppy IndexDB can save me here, to speed my browser, if i save to IndexDB instead of states.

How does one save the results of a shifted list to the database? Currently every time I try to save the list to a list field in my DB it only does it every other shift. When I refresh the list resets back to the original sort order. Is there a way I can trigger a workflow off of the fact that the list order has changed as a result of shift?

Any help is appreciated, As most experienced users can say the difference. If it worth a try, it requires lot of changes in the app structure. So before invest and make changes a guidance is required. Plugin owner @keith or anyone

Hi keith, started using Floppy and it’s been good so far, up until now. my use case involves using the drag and drop feature within nested repeating groups. the first repeating group’s dragging works fine, however, the one inside cannot be dragged. i set up the nested rg’s dragging by putting a floppy inside the outer rg so that each one had its own floppy, then in the inside rg, i set the element id’s of the rg and rg group to contain the index of the first repeating group. however, apart from the first nested rg , none of the other nested repeating groups’ groups can be dragged. Wondering what can be done here, thanks.

Hey @Nakita: Floppy isn’t designed to “speed things up”. Whether it would or not in your application depends on many many factors and how, exactly, you make use of it.

So I can’t answer your question. But I would be inclined to say it’s unlikely to have the impact you’re imagining.

That being said, the things it IS designed to do it does quite well. :man_shrugging:

Hey @nachodip97: nesting draggable RGs isn’t something Floppy was designed to support. I wouldn’t imagine doing that sort of thing, so didn’t design it to do that, it hasn’t been tested by me in such a scenario, and so I would assume that it doesn’t work.

Hey Keith, I’m running into an issue with the rehydrator. I have a list of many IDs and one of them doesn’t exist in bubble (or so I believe). I get this error in the console and the workflow fails:

Plugin action Floppy Rehydrator SSA error:
TypeError: Cannot read properties of null (reading ‘_id’)

Any help is appreciated!

Hi @keith or anyone who can help me. I’m currently using the List Shifter to sort a list by fields that are related to another Datatype. It works perfectly, I’m using the SORT action and switching between descending yes and no, everything is fine with that.

The problem happens if I filter the list using a specific filter (before or after the sorting). When I filter, the sort action no longer has any effect. At the moment, the original list has the filtering constraints and this list is passed as source to the List Shifter. The RG then receives the list processed by the List Shifter "Shifted List.

I’ve already tried applying the sorting to the original list and the filters in the RG itself, applied to the processed list, but the same thing happens. Am I missing something here? Should I use two List Shifter for this or some other plugin action?

Thanks in advance for any help.

EDIT: This message was for the plugin “Toolbox plugin” and List Item Expression" by @mishav but I paste it here to explain the context of my next message, as I finally used the FLOPPY plugin…

Is it possible to create a new list of Bubble items using the List Item Expression (Toolbox plugin), but with a new field added to the output list so I can use this field on the page to sort or filter the list (with the same Bubble Type as the Things in database), and without having to actually modify the database items?

Explanations:
I have a map displayed on my app that can be explored by users, and I need to update the list of places that should be displayed, and sort them according to the distance from map center.

Currently, we use this action:

This would be great to:

  • Sort places by distance from the map center as a dynamic value computed in the List Item Expression (using custom JS formulas in the “item expression”)
  • Be able to use the output list instead of the input list in other Bubble elements or workflows on the same page (only in frontend, I don’t need to edit the items in database)
  • Get rid of the “sort by Adresse” + “distance from MapCenter” in the “Search for” action that consumes a lot of WU and google geocode API calls (expensive billing because we have +1500 list items in database and the workflow is triggered very often)…

But I’m not sure how to create and use other fields that are not defined in the Data Type, and still use items as Bubble Things to be able to use them in other Bubble elements and workflows.

I saw that there is an option to sort list items according to a dynamic field name in the :sorted operator for lists in frontend, maybe can I use this to sort according to the new “distanceFromMapCenter” field created in the List Item Expression?

Thanks for any help or advice on how to manipulate/change/sort/filter list of Bubble Items with List Item Expression!

PS: Saving the distance in the database is not possible as it’s a dynamic value that changes for each user and map view.

EDIT (related to previous message): I managed to do this, but do you think of a better way to improve performance and reduce processing and sorting time ?

  1. Add List Shifter Pro element on the page with:
  • List to shift = list of Things (Data Type of List = Annonce) to sort (which is the result of a “search for Annonces” saved on page state “Annonces” in workflow action)
  • Process Output Type = number
  1. Process the list to sort with a workflow action “PROCESS List SlistShifter” on this List Shifter element:
  • Add a pause of 100ms before this action (I don’t like it but I couldn’t get this to work correctly without this pause, maybe because without pause, Bubble triggered the event too soon and the list didn’t have enough time to be saved to page state before the process started)
  • List to iterate over = Original List
  • Use a Long Text Constant to run custom Javascript code on step 1 Operand X along with Step 1 Operator defined as “eval(x) aka Run Javascript”
  • Push RS1 to Processed List


    NB: It was tricky but I worked around Bubble limitations to create a JS list of coordinates [[lat1, lng1], [lat2, lng2] …] with Bubble expressions “Annonces :format as text” and then split() and the use of the variable “i” to retrieve the correct item thanks to its index.

:confused: I couldn’t find a way to use the plugin variable “i” for current iteration and item index inside a Bubble expression like “Annonces’s item #” and “arbitrary text” as it was converted to text and not evaluated as a variable.
But if you know how to do it it would be helpful to avoid using the whole list for every iteration!

  1. Use "A ListShifterPRO Processing Complete" event in workflows to trigger the action “SORT List ListShifterPRO” on the same element with:
  1. Finally use "A ListShifterPRO Sort Complete" event to do some stuff on my app when sorting is complete (like mark loading of list as fully completed)

@keith I had a bug in console with your plugin, saying that " ps_type_list_constant is not defined at Object.t las funcEvals]"
This error occurs every time I set the “Active DEBUG” option to “yes” (true). I think it’s just a typo and you wrote ps_type_list_constant instead of pl_type_list_constant in the console logs.

Note to future self: Bubble native search does a db search so you can use it to hide some sensitive data from the user while still search / filtering based on that hidden field. You can’t do the same with Floppy since floppy won’t have that info.

1 Like

Hey @keith , we are using listshifter with a condition on the workflow to only run when it is initialized, however when we trigger the workflow, it triggers as if it is initialized but we receive an error in the console saying it is not in fact initialized. Not sure if we’re doing something wrong on our end.

Checking condition in debugger

Then we receive this error once the workflow runs
image

None of the videos in this thread are working anymore (all read 0:00 length and won’t let me hit play, although I see an image). Is this the case for others? I have no clue how to use this plugin otherwise :laughing:

1 Like