We’ve built a helpdesk system. On the index, the list of tickets are listed in an RG. There are different views available, like “my requests”, or “assigned to me” or “my team’s” each showing different segments of the tickets. There is also a number of filters that are available, to filter tickets by category and so on.
You may notice the filter applied at the end, this is to filter by search terms from the search bar.
Problem:
When switching view for the first time after page load, it takes “forever” to load the list of tickets. After switching view the first time, then it’s going at a good pace, which tells me it’s an RG thing at step 2 and not the custom states set in step 1.
Hi, thanks for sharing this video. Did you record it just to reply to this post?
I like your filtering system, especially because it also triggers right when options are selected.
However, I’m afraid it is not addressing my issue (unless I am missing something about what you presented). The reason is that the filtering of the ticket list is quick fast and smooth.
My issue really is with the view switch at the top, and the initial load of the RG. Once the RG is loaded initially, it runs quite fast. There’s something about the first time loading of data that takes more time than usual.
I might be missing out on something but here’s my take
If the speed of filtering is not your issue, and it’s solely the slow initial load, I guess you would have to check your data structure? There are a lot of nuances when it comes to RG load speed, factors such as: Size of the data being loaded in to the RG, Initial search structure, filters, number and type of elements in the cells, not utilizing styles in the elements in the RG, and a bit more.
I haven’t seen your DB structure but if you’re not utilizing satellite data types for your RGs, I would suggest you check it out. However, if you think your DB structure is already optimized, then I would have a look at the other factors that I have mentioned.
Also, I highly suggest you use the daisy chain filtering method as what @rico.trevisan just showed. Been using it for quite some time and I’m in love with it
To be clear, that video is from @Andrew.Vernon (I just fixed my original post with it).
@umiumansa : I would suggest not pulling too much data into states. I once ran into problems with an application where I did that. With 10’s of items not an issue. The moment that started to grow past 100’s, the browser cache would fill up quickly and all sorts of weird things would happen; mobile browser crashed, laptops hung for a few seconds.
And I think that when you put stuff in states it looses its direct connection with the database. I think that’s what I once read in one of @keith’s technical opuses.
I’m not following this thread closely, but I did look at @umiumansa’s video. When you see the “blue bar of death” like that it means that you are loading a large amount of data. That is, either you’re loading a s-ton of items or you’re not loading that many items, but the individual items have some heavy fields on them (e.g., as when one attaches a list of images directly on some datatype, which is generally a bad idea).
In @umiumansa’s case, they are doing Search for Tickets :filtered. Unless there are some constraints inside that Search that they did not show in their screenshots, what this will do is download ALL TICKETS in the database to the browser. That’s the only way that :filter can work.
If they want the initial load time to be shorter, they need to move some constraints into the initial Search so that the database doesn’t have to send every damn thing to the browser. Or only load the data that’s requested, when it is actually requested. It’s that simple.
As for your comment about custom states, @rico.trevisan, yes custom states only update when we Set them. If we set a custom state to be the results of a Search, the data held in the custom state is static rather than a live query to the database. So, if for example we stored Search for all Tickets in a custom state, if a new Ticket is created, the state will not magically update until we do it ourselves.
(There’s an additional subtlety: Things are also live queries [their primary fields will update if changed in the database]. So, if you’re storing a list of Things in a custom state and one of them gets deleted, the item at that Things position is still reflected in the list, but the Thing itself no longer exists and we would see its fields as all being empty. This is documented in the note at the bottom of Using Custom States - Bubble Docs. )
As for “pulling too much data into states”, of course browser memory is finite and there’s a lot of ways that we can crash the browser or blow up the call stack. In Bubble the most common way to do this is loading way more data than we have memory for (like what the OP is at risk of doing at scale).
The only thing I can imagine would take some time could be attachments which are currently a list of files and which I am planning to move to a related table. However, looking at the tickets, only a couple of them have attachments out of 109.
Insane… At this point, @keith should very well publish a book about Bubble - pretty sure it’s gonna be funny as hell too!
Is there possibility that Bubble would add dynamic expressions to states? Recently ran into a roadblock that would’ve been very easy to solve if state values could be dynamically set
Haven’t really dived too deep to your issue but maybe you should try utilizing satellite data types for your search instead?
If current cell’s ticket is clicked, you could simply redirect them to a dedicated ticket page, popup, or group containing the current cell’s ticket parent data type
Oh, and I suggest you apply what Keith said in his reply
Well if you want something that holds data like a custom state but that automatically updates when the value of the expression changes, you can use List Shifter or Floppy Expression Watcher (from my Floppy plugin) .
Both of those take a list and / or scalar expression and publish the values to one or more outputs whenever the values change. They also throw an Initialized/Updated event so you know when that has happened.
(This is all that Floppy Expression Watcher does. List Shifter has additional features for list transformation.)
Edit: I suppose Groups also have this capability but they don’t actively generate an event when data changes, though you can watch for that using other techniques. I just find this easier with a dedicated plugin.
I set the Refresh value to NO and thus limiting the app to only refreshing the filter without refreshing the RG data and the issue persists. So it is not an issue with the RG but with the management of filters in states.
By toggling some of the fitler values on and off, I see those that are time consiming are:
Domains: this one is searching for the list of ticket domains (topics) that belong to the current user’s team, by searching all the memberships of this user and getting the domain for each of these memberships.
Assignees: this one is searching for the list of users that are in the team of the current user. This one will look for the users in the domains the current user is a member of. So it will look for all members ships where the domains are the domains of the current user:
So looking back it may be down to the pulling of data into states as @rico.trevisan suggested and so the chain filtering may be the solution. I’ll do some tests to validate this hypothesis.
So after realizing my storage of search criteria in state is the cause of the slow down, I am looking again at your video. What I do not get from the video is where you store the search criteria. For example in my app I will store the selected statuses in a “statuses” state of the search and filtering group, whenever I save the desired filters select in this popup:
That would still be the case if I use chain filtering right? The custom event will need to look for the criteria so they need to be stored somewhere on the front end.
When resetting the filters I would need to repopulate the custom state with all filters then too, right?
When storing the status it’s not a big deal, as it’s a small finite set, but the issue is when filtering requestors, or assignees or domains for tickets as these are dynamic lists that contain more data.
Somehow I would need to store the requestor users to include and exclude from the search. If I exclude one it means storing either storing one excluded or storing a lot of included, and the opposite for exlclude all except one. I suppose the default would be to include all, in which case the can use an empty state as the equivalent of including all and skipping the search by requestor when the state is empty.
Take also the case of filtering by domains (which are topics of tickets). When switching to the Team View, I need:
The list of tickets related to domains to which the current user belongs.
The list of domains to which the current user belongs (to display as filter options in the filtering).
The list of domains to exclude (filtered out).
The two lists of domains would need to be stored in state wouldn’t they?
The defaults are saved in each individual element. For instance, if you have a drop down for task status, it will revert to whatever you have set in the default of that element.
I appreciate how you been approaching the forum. Clear questions, lots of information, you try a proposed solution and revert back with your findings. High quality stuff.
Here is a bearhug ticket , redeemable at any helpful forum regular near you.
So I’ve completed the changes and it’s a lot smoother now! Thanks.
Here are things learned, in case it serves in the future:
I made the mistake of storing too much on states, though some filtering is required in states, it is slowing down performance. To be more precise, I made the mistake of storing the “included” values, rather than “excluded” values. So the best is to assumed the user wants all data (i.e. blank state storage) and add to the state the values that need to be excluded from the filtering.
The chain filtering seems to help indeed. It’s counter-intuitive, as it seems to make a lot of unecessary calls, but it is efficient. The part that surely helps I asusme, is that we filter the group’s own data and feed it back to the group, which makes the dataset ever narrower.
Although I have not done so at the moment, using proxy data types for the search (or sattelites as called above) may make the app more efficient searching and loading the dataset.