How to dynamically update a Select component’s options based on another Select’s value?

Hi all,

I’m trying to dynamically update the options of a Select component (subcategoriaFiltro) based on the selected value from another Select (categoriaFiltro).

I wrote a JavaScript query like this:

const subcategoriasPorCategoria = {
  "maquillaje": ["ojos", "labios", "rostro", "accesorios", "uñas"],
  "cuidado de la piel": [
    "Arrugas y Líneas Finas",
    "Piel Grasosa",
    "Resequedad",
    "Piel Sensible",
    "Manchas Oscuras",
    "Imperfecciones",
    "Piel Propensa al Acné"
  ],
  "nutrición": [
    "malteadas complete blend",
    "matcha",
    "cafés delish",
    "suplementos nutriplus",
    "recetario nutriplus",
    "gummies"
  ],
  "cuidado personal": [
    "jabones",
    "cuidado de manos y pies",
    "gel de baño",
    "cuidado bucal",
    "fragancias",
    "baño y cuidado corporal",
    "protección solar",
    "gel de masaje",
    "aceites esenciales"
  ],
  "cabello": [
    "shampoo",
    "acondicionadores y mascarillas capilares",
    "aceites, sueros y aerosoles"
  ],
  "hombres": [
    "cuidado personal",
    "fragancias"
  ]
};

// Get selected category
const categoriaSeleccionada = categoriaFiltro.value;

// Get corresponding subcategories
const subcategorias = subcategoriasPorCategoria[categoriaSeleccionada] || [];

// Assign to subcategoriaFiltro
subcategoriaFiltro.setOptions(subcategorias.map(sc => ({ label: sc, value: sc })));

But I get this error:

subcategoriaFiltro.setOptions is not a function

I assumed .setOptions() would work based on other Retool examples, but it seems that may not apply here.

Any idea how I can update the options of one Select based on another?

Should I be using temporary state, or is there a more idiomatic Retool way to do this? I want this to happen automatically when the user changes the category selection.

Thanks in advance!

Edit:
I made two transformers, but the program's still not working. This is what I have so far:

1 Like

Hey there @max.lopezzz,

I would approach this in either of the following ways:

1-

  • Make your JS query a transformer which will change dynamically without need of triggering it, and replace the setOptions line with return subcategorias
  • Reference your transformer directly in your component, as {{ transformer1.value }}. You can dynamically set your component's data set by clicking on the FX next to the data source field
  • Add your subcategorias to a variable that you can reference from other components
  • Apply the filter directly in your subcategoriaFiltro component by selecting the FX dynamic button and adding something like {{ variable1.value[ categoriaFiltro.value ] }}

Hope this helps!

Hey @max.lopezzz ,

Since you're using an object format like:

const subcategoriasPorCategoria = {
  "maquillaje": ["ojos", "labios", "rostro", "accesorios", "uñas"],
  "cuidado de la piel": [
    "Arrugas y Líneas Finas",
    "Piel Grasosa",
    "Resequedad",
    "Piel Sensible",
    "Manchas Oscuras",
    "Imperfecciones",
    "Piel Propensa al Acné"
  ],
  "nutrición": [
    "malteadas complete blend",
    "matcha",
    "cafés delish",
    "suplementos nutriplus",
    "recetario nutriplus",
    "gummies"
  ],
  "cuidado personal": [
    "jabones",
    "cuidado de manos y pies",
    "gel de baño",
    "cuidado bucal",
    "fragancias",
    "baño y cuidado corporal",
    "protección solar",
    "gel de masaje",
    "aceites esenciales"
  ],
  "cabello": [
    "shampoo",
    "acondicionadores y mascarillas capilares",
    "aceites, sueros y aerosoles"
  ],
  "hombres": [
    "cuidado personal",
    "fragancias"
  ]
};

return subcategoriasPorCategoria

You can easily implement conditional dropdowns in Retool by setting your Subcategory dropdown's values to something like this by using transformer:

return {{(sampleData.data[select2.value] || []).map(sub => ({
  label: sub,
  value: sub
}))
}};

This will dynamically populate the subcategories based on the selected category from your select dropdown.

And for your Category dropdown, just take another transformer:

return {{Object.keys(sampleData.data).map(cat => ({ label: cat, value: cat }))}};

:camera_flash: Here are some screenshots showing how the select components are set up:

:video_camera: Here’s a screen recording showing how this works:

Let me know if you need any help — happy to help! :raised_hands:

I can't find where to input the data source :frowning:

1 Like

Hey @max.lopezzz,

Thanks for your response!

Here's a step-by-step guide on how I implemented dynamic dependent dropdowns in the mobile app:

1. Using JavaScript and Transformer

I reused the same JavaScript logic and transformer setup that I previously shared in the earlier response. This ensures consistency between the web and mobile app implementations.

2. Category Select Component

For the Category dropdown, I used the following bindings to dynamically populate the options:

  • Value:
{{ category_select_values.value.map(item => item.value) }}
  • Label:
{{ category_select_values.value.map(item => item.label) }}

This ensures that each option in the dropdown has the correct internal value and user-facing label based on the transformed data.

3. Sub-Category Select Component

Similarly, for the Sub-Category dropdown, I used:

  • Value:
{{ sub_category_select_values.value.map(item => item.value) }}
  • Label:
{{ sub_category_select_values.value.map(item => item.label) }}

This dynamically updates the sub-category options based on the selected category, maintaining the dependent dropdown behavior in the mobile UI.

4. Screenshots for Reference

Here are some screenshots to give you a visual idea of how it looks on the mobile app:

  • Category and sub-category dropdowns with dependent logic
  • Dynamic values updating based on selection

Let me know if you need more help — happy to help!

I'm getting these errors:

Hey @max.lopezzz - I put together a quick example that might be simpler than what you've been trying to do thus far. You're definitely on the right track, though. :+1:

Assuming your category data is stored as an object where the keys are parent categories and the values are arrays of children, you should be able to simply set the value of your parent and child selectors to {{ Object.keys(categoryData.value) }} and {{ categoryData.value[select1.value] }}, respectively.

Give that a shot and let me know if you have any questions.

Thank you so much!

1 Like