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

Hey @app11 im glad you got it sorted, and that seems like the right approach to me. Thanks for using Floppy!

2 Likes

Bugfix Update! Just pushed Floppy version 1.9.53, which fixes a bug in the Utility: List Math action in Floppy. If zero (0) was provided as a value for “Scalar 2” in any operation step, the value was not recognized, leading to unpredictable results (usually undefined). This has been fixed.

Thanks to Floppy user @andrepaganotto for the bug report on this one.

2 Likes

BTW, the same issue can happen in List Math SSA, and there will be a version that fixes that, too, but it’s not available just yet (1.9.54 is bugged so use 1.9.53 or 55 which are identical and fix List Math in Floppy).

Update: OK, just pushed 1.9.56, which fixes the problem with Scalar 2 values being 0 and not returning correct results in the List Math SSA. (This was fixed in List Math action of Floppy in previous version 1.9.53. New version fixes both the client and server-side versions of that element-action and server-side-action.)

Kinda related to this, @ankur1 and I were trying to make Floppy’s drag’n’drop work directly with an external API – can it?

The drag function works, but the 2nd group shows no data.

CleanShot 2023-07-25 at 14.09.45

You can inspect that item and see that the data has an ID, but I can’t grab on to it.

The localStorage data are empty objects

So the solution in such a case would be to do the same as you suggested to Future - is that correct:

  1. capture the API response as a string
  2. use that as the data source/type of the Floppies
  3. create an endpoint that parses that data
  4. use this endpoint to fill in the group inside the RG

Another question: is there a way to know which item was dragged?

1 Like

Hi @keith,

Run into another challenge I have not yet solved.

I have setup some scalar values in indexeddb. I have set the key to a unique user ID with the idea that multiple users on the same pc can login in and find their personal data loaded into the browser.

I was able to isolate the specific values per user when dealing with a list. I used :filter for it. But this is not possible for Scalar values so it seems? Anyway, I have still not figured out how to do it.

What happens now is that I do a check if a certain scalar value exist. But in case there are multiple users and therefore multiple scalar values the system simply sees the value I check for and the workflow does not run.

So somehow I try to understand how to check if a scalar value of a specific key equals a specific users and if the value is equal to something.

Can you give me some pointers as to how to do this?

Hey @rico.trevisan, so yeah, API response objects are like Things but they have no unique ID, so they are not serializable into anything, so they cannot be stored in browser storage. You can, however, take some basic field and store that. For example, My API Response Objects’s Name would resolve to a list of texts (strings) if such a field existed.

But this is orthogonal to drag/drop. What’s probably happening is I’m not recognizing the API responses properly (it is easy to misidentify them as Things and do the wrong thing). Theoretically, it should be possible to fix drag/drop to work with API response objects.

1 Like

Hey @app11, well, when you’re using IndexedDB, you do have three different parameters to work with. Now, I haven’t tested/used/abused Floppy much in this way, but here’s what I’m thinking:

Keep in mind that you basically have a folder structure with:

Database > Datastore > Individual Keys

So, one thing you could try is to use the user’s unique ID as the Datastore name. Note that those values in the main interface can be dynamic expressions. And then, when you wrote some specific key name, it would be written to that specific datastore rather than some other datastore. (And similarly, retrieved keys would come from the given datastore.)

That’s a possible approach. (Note that I would not recommend making the Database name dynamic.) So you’d end up with your IndexedDB looking like:

Database > User 1 Datastore > User 1's keys
----------> User 2 Datastore > User 2's keys
etc.
----------> App Data Shared by All Users > App Data keys

Like I say, I haven’t really played around with this sort of idea much (that’s not really a design goal for Floppy as it stands), but conceivably this could work.

… and, actually, @rico.trevisan, I think there’s an additional problem with making drag/drop work with API Response Objects. This is basically “the API ghetto” problem as I sometimes refer to it.

If you have some Bubble API call that returns some single object, you basically now have a datatype that represents a single instance of that object.

But if you have some Bubble API call that returns an array (a list), you now have a datatype that represents a list of some sub-objects. For example, it looks like you have an API call that gives you back a list of “team members” or “users” or some such. While your app now has a data type for a “List of API Users”, there is in fact no data type for the individual Users in the list. And so, these literally cannot be individually moved from one list to another and you can’t, in fact, create new lists of those objects.

That is, these sorts of lists can only come from the API connector and can’t be generated or modified otherwise (including inside the plugin API). It’s a dumb problem, but it is what it is.

2 Likes

Thanks @keith for sharing!

I was unable to see how I could structure an expression with scalar values like you suggest though. Perhaps I missed something. Will have another look.

As you said that this use case was not the goal of Floppy, how would you handle cases in which you want to store data locally that belong to a user, like the onboarding flow you suggested, in a world where multiple users use the same computer/browser?

Well, essentially, this is not the assumption made by sessionStorage and localStorage. They are for storing values related to “this particular browser/device”, not a more granular level.

Now IndexedDB is a little different, but we cannot at present build a meaningful Bubble plugin that supports it fully, due to various Bubble limitations. So Floppy’s implementation of IndexedDB uses a library called “localforage” that has a very localStorage-like interface to IndexedDB.

What I’m suggesting is like the following example:
https://list-shifter-dev-test.bubbleapps.io/version-test/floppy_user_datastores?debug_mode=true

I do a QUICK walkthrough about how I did this in the following video about dynamically setting the datastore when using Floppy with IndexedDB:

:point_up:oh wow, and sort of freaky… Loom writes AI-generated descriptions based on what you said in the video. Wild.

1 Like

@keith , if we pass the unique id into the api response something like this.-

[
  {
    "id": 1,
    "event_name": "abc"
  },
  {
    "id": 2,
    "event_name": "zyz"
  }
]

and pass that “id” field to floppy plugin so that plugin identify which key contains the unique value.
then it is possible to drag/drop via the API response?

@ankur1:

Unfortunately that won’t help.

1 Like

@keith so there is no way to do this? There should be some way.

Yes, but you’d be referencing some proxy for the API response (email address for example) and then, to turn that back into (“rehydrate”) your app’s API data type, you’d call the API, saying, “give me the list of THESE users with THESE emails”. Depends on what the API supports.

Just like dear old Tyrell, I’ve been ‘round and ‘round on this. And the subject always gets a virus and dies on the table.

2 Likes

@keith Also how can we know which item is dragged if we are using the Bubble data type.

@keith Thank you for the intricate documentation. I just have a couple questions I was hoping you could answer which wasn’t evident in the videos.

I have an application that has a large database of “Things” and each thing has a number of attributes. A user can display, and view a filtered list of these things based on a number of different categories. I am seeing that a lot of my usage is being used to display and manipulate these lists. I originally was using a “do search for” for each condition and then moved towards an RG with a :filtered to minimize the search with the database.

Does the floppy RAM function the same as filtering a RG or state and using that as a data source? If I was trying to display a list of 10,000 items to a user which varies by user and user type as well as the data type, what would be the best way to Floppyize it?

Also, Is there a reason that you do not use the sorted or filtered at the end of a floppy list in your videos? It appears you reset the list each time a user action is made instead of adding on a :Filtered or :sort. What is the reasoning for this?

Really appreciate the work!

@keith

Much appreciated!

I do have an issue though. In your video, great explaination and all, you set the value and look it up. In my case I would like to have a workflow that does make sure that in case the key value is not in the browser anymore (deleted by the user or another event) for a particular user, it is added again. So I setup a workflow that runs as soon as the floppy is initialized. I then need to check if a certain key value is available or not. If not, it needs to be added. If it is there but not populated, it needs to be filled.

In order to do so I have tried I think all possible expression combo’s. Tested for hours but no luck. It is hard to summarize hours of trying and testing but at least this is what I have found:

  • scalar value (storage) yes/no type can not set to “empty” when using the expression. You can format it to a number but then “no” equals “no” but also “empty” (field not set yet) and therefore not usable to test if a value yes/no exist or if it is empty. Therefore I was not able to use the value to test if I needed to add a key and populate it.

  • running a function like [floppy_notification] → ‘keys found in storage’:filtered:count is 0 does not seem to work either. Filtered does the check if the key “notification” is part of ‘keys found in storage’. Which, when there is not entry is not the case. The workflow in this case will run as expected. Since there is an entry after the workflow has ran, the count is 0 is not true anymore as there is at least one entry “notifications”. Still, the workflow runs. Somehow it does not respect the 0 in this?

  • I also tried the easier [floppy_notification] → 'keys found in storage doesnt contain “a particular key”. So if a key is not in the indexeddb of the user (doenst contain) the workflow should run. However, the workflow runs all the time. Also when the keys found in storage returns the “particular key”.

  • I also tried to put Floppy_reader in to the equation. No luck either.

  • In all the cases, writing the values in a text files show that for instance ‘keys found in storage’ is indeed populated with the key I test for. But stil, the “only when” expression box of the workflow is not respected.

  • Another think I noticed during hours or testing and browser refreshes is that sometimes a workflow runs and sometimes it does not. I have 4 floppy’s setup and sometimes 2 run then 4 etc. Also, on some ‘pages’ (SPA with url navigation) it runs while on other pages it does not.

I have tried lots and lots of combinations for hours so perhaps I am missing something simple here. Happy to test more but in that case I need to know what to test because I have no idea anymore.

I hope it is a bug and that I have helped the community and you @keith :wink:

If the key value is deleted, how would you recover it? Is it stored in the database?

Note: when a key goes empty, the key itself is removed, because that’s the same thing in browser storage. That is, let’s say there’s a key “nothing” that is empty, well, if we ask for the value of the key we will get empty. If we query the value of a key that doesn’t exist, we also get empty. So it’s the same thing either way.

Well, I have setup the data store with the user ID. Inside that data store I expect a number of keys. One of them is for instance a yes/no for notifications.

Now I want to check if that key, notifications, is in data store of that user ID.

So I set up a workflow that runs as soon as the floppy is initialized. I then add the key but only when that key is not in the stored keys.

This way I was thinking that we can have a robust way of making sure that the key is always there to write to because if not it will brake the app or at least give unwanted behavior.

So the user enters the page, the user is logged in so the floppy uses data store called “userID of that logged in user” and when initialized is yes I check if all the keys that need to be there are present. If not, I load them and populate the keys with one fetch from the db.

So I need to somehow be able to run a “Only when” expression that will tell me if the key is there or if the value is empty. Which I cannot get to work.