New version of the Cascader component
Available on Retool Cloud.
A new and improved version of the Cascader component is now available on Retool Cloud and for self-hosted organizations. Retool recommends using the new component, and the legacy version will be deprecated. You can click Upgrade in the Inspector of an existing Cascader component to use the new version.
The new Cascader features:
- The ability to manually add an option list or dynamically map one to existing data.
- A new dropdown look, similar to the Select component.
- New label options (customizeable caption, color, icon).
- Options now support numeric values in addition to string values.
Some additional changes in this version include:
- The
value
of the new Cascader component is thevalue
of the selected option. A newvaluePath
property enables you to have access to the path of values leading to the selected option. - Option values must be unique.
- Like other modern Retool components, values for options need to be unique. If you use the one-click upgrade for Cascaders, duplicate values will have parent values appended to make them unique.
- Like Checkbox Group and Navigation, the data source is expected to be an array of objects with a property that points to its parent. Cascader nests options by parent value.
If your legacy Cascader component uses dynamic data (like the output of a query), you need to manually transform your data to be compatible with the new component. To do so, you can use one of the following JavaScript functions, depending on the data structure of your data.
- Array of arrays of strings
- Arrays of objects
Migrates string[][] to { value: string, label?: string, parentValue?: string }[]
function migrateSimpleStructureToCascader2(structure) {
let options = []
const keyToValueMap = new Map()
const uniqueValues = new Set()
for (const leafNodePath of structure) {
for (let i = 0; i < leafNodePath.length; i++) {
const key = leafNodePath.slice(0, i + 1).join('-')
if (keyToValueMap.has(key)) continue
// If the value is not unique, we use the key
const originalValue = leafNodePath[i]
const isNotUniqueValue = uniqueValues.has(originalValue)
const value = isNotUniqueValue ? key : originalValue
// Track the option to its potentially changed value
keyToValueMap.set(key, value)
const parentKey = i === 0 ? undefined : leafNodePath.slice(0, i).join('-')
const parentValue = parentKey ? keyToValueMap.get(parentKey) : undefined
const option = {
value,
label: isNotUniqueValue ? originalValue : undefined,
parentValue,
}
options.push(option)
uniqueValues.add(value)
}
}
return options;
}
Migrates { value: string, label?: string, children: { value: string, label?: string }[] }[] to { value: string, label?: string, parentValue?: string }[]
function migrateComplexStructureToCascader2(structure)
{
let options = []
const uniqueValues = new Set()
function recursivelyCreateOptions(
originalOption,
{
options, // Array to add the new option to
uniqueValues, // Set to keep track of unique values
parentValue,
},
) {
let value = originalOption.value
if (value === undefined) return { options, uniqueValues }
// If the value is not unique, we make it unique by appending the parent key
if (uniqueValues.has(value)) {
value = `${parentValue}-${value}`
}
// Use explicit label if it exists. Otherwise, if we altered the value to make it unique, use the original value as the label
let label = originalOption.label
if (!label && originalOption.value !== value) {
label = originalOption.value
}
const option = {
value,
label,
parentValue,
}
options.push(option)
uniqueValues.add(value)
// Create options for children, this can be recursive
if (originalOption.children) {
for (const child of originalOption.children) {
const recursiveResult = recursivelyCreateOptions(child, { options, uniqueValues, parentValue: value })
options = recursiveResult.options
uniqueValues = recursiveResult.uniqueValues
}
}
return { options, uniqueValues }
}
for (const oldOption of structure) {
options = recursivelyCreateOptions(oldOption, { options, uniqueValues }).options
}
return options
}