HowTo: loading & disable state in collections

Hi :wave:t2:

It took me some time to figure this out so I wanted to share this with you guys. Perhaps it can help you.

The problem I faced was that I wasn’t able to simply alter the UI state of the nested components in a collection list. Whenever I used isFetching.. all buttons in the list showed a loading indicator. What I actually wanted was only one to show the loading state.

So here’s my setup:

yourOwnResourceQuery = Resource query
variable = retool variable (temporary state), store custom item data related to UI state
lastPicked = retool variable (temporary state), store id of last clicked
item = references the current item that was clicked in a custom collection list in the run script section on the event handler

Click handler custom collection list buttons:

// set item as picked
variable.setIn([variable.value.findIndex(x =>x.id === item.id),"picked"], true);

// was picked last
lastPicked.setValue(item.id);

// update your database or do something else
yourOwnResourceQuery.trigger({
   additionalScope: {
      primary_key: item.id,
      somethingElse: item.title
   }
});

This is used to disable the button if it’s already picked:

{{variable.value.find((element)=> element.id === item.id ).picked}}

I use a picked property instead of a simple array with IDs to be able to add new UI properties later. You can have multiple buttons or other components that need a different state based on other values than picked

This is used to show the loading state for only the button that was clicked last. Otherwise, all buttons loading state will be set to true:

{{yourOwnResourceQuery.isFetching && lastPicked.value === item.id}}

In this screencast you can see that the second + button is clicked. The loading state is activated and the button icon is changed afterwards. The button is also disabled.
All other buttons are still enabled.
Clicking the first + button will activate the loading state of that button. The second button stays disabled and doesn’t show a loading state.

image

The following screencast is what I had before. I used the following:

yourOwnResourceQuery.isFetching
&& variable.setIn([variable.value.findIndex(x =>x.id === item.id),"picked"], true)

Here's what you will get then:
C6243292-AD63-45D1-A31A-F0E31617D0E4

Notice that the loading state is activated for both items that were clicked. This is what you don't want.

Last but not least: the button icon :fireworks:

{{variable.value.find((element)=> element.id === item.id).picked ? 
 "/icon:bold/interface-validation-check-alternate" 
 :  "/icon:bold/interface-add-1"  }}

It's as simple as that. You can place that code instead of an icon when you click on add button next to add-ons (button component properties). The first value is used when .picked is set to TRUE. If FALSE it will return the second value.

Ignore the red error in the screenshot. I use different variable names in my own code. So in the screenshot it throws an error, but it shouldn't for your own code.

You can always use isFetch without anything else. But then this happens:
6977A787-79BD-4C45-AE7E-A5FC17435D15

If anyone has a different solution or a more eloquent approach, I would really like to see it! :innocent:

5 Likes

Thank you for sharing your implementation! :heart:

2 Likes