Bubble up selected items in a multiselect listbox component

Hello there!

I'm having some hard time solving this one. I have built a Retool app and used several multiselect listbox components. Items are both selected manually and programmatically in ordered lists that are often long.

To improve the overall readability of the app and get as quickly as possible which items have been selected, I'd like to push those selected items to the top of the multiselect listbox components.

How can I do this?
Thanks for your help!

Hey @jeremy! So I read this and thought it would be a good challenge but certainly feasible. I set out by writing a JS transformer to sort an array of options by the array of selected items in the multi-select listbox:

let optionsArray = {{query1.data.options}};
let selectionsArray = {{multiselectListbox.selectedItems}}

let sortedArray = optionsArray.sort((a, b) => {
  const aIndex = selectionsArray.indexOf(a);
  const bIndex = selectionsArray.indexOf(b);
  if (aIndex === -1) {
    return 1;
  }
  if (bIndex === -1) {
    return -1;
  }
  return aIndex - bIndex;
});

return sortedArray

Then I set the listbox's data source to this transformer. Unfortunately, I'd not recognised that this would of course result in a circular dependency, whereby selected items are sorting the data source, but the data source is sorting the items, in general.

As far as I can tell, there isn't a way to get around circular dependency, but I'd be very happy to be proven wrong!

I think the lovely people at Retool would need to add this option to multi-select components so that selected items are rendered at the top of the options list, without actually changing the order of the options array under-the-hood.

#feature-requests

1 Like

Hi @ryanm, thanks for your help!

I've tried to test out your transformer script but it didn't work. Just to make sure I did get what you mean:

Is let optionsArray = {{query1.data.options}}; a variable where you'd like to store the array of labels prompted in the components?

There's a property called selectedIndexes that could be handy here:

The problem is I'm not sure I can set a new value in selectedIndexes to move the selected item to the top. And even if I could, what happens when I'll unselect the option? I feel like it might exist a workaround with a temporary state to store previous & new indexes.

Anyway, thanks for your help, I'll keep digging.

Just filed this as a feature request internally! Thank you for flagging @jeremy and thank you for sharing such a clever workaround @ryanm.

As a worse and less functional workaround, depending on your use case, you could add another Multiselect Listbox and set its value to {{multiselectListbox1.selectedItems}} and its default value to {{multiselectListbox2.values}} to select all values by default.

This is not a great workaround, but I wanted to share juuust in case it helps :sweat_smile:

1 Like