I have a menu from which a user will have to pick a single option off of every row.
Mockup:
This menu is represented in data like this:
menu = [
[41, 36, 573, 572],
[47, 96, 79],
[480, 479]
]
The number of rows is variable, as is the number of options in each. The numbers that represent each option are always unique.
The issue is that not every combination is valid. I have a list of the "allowed" combinations available like this:
variants = [
[36, 47, 480],
[41, 96, 480],
[41, 79, 479],
[41, 47, 479],
[572, 47, 479],
[573, 47, 479],
]
I have access to an array that grows with each choice selected:
options = []
options = [41]
options = [41, 47]
options = [41, 47, 479]
Because not every combination is valid, menu options that would result in invalid combinations must be disabled, so given the options
array, I need an algorithm that generates a data structure like this:
menu_toggles = [
[true, true, true, true],
[true, false, true],
[false, true]
]
This structure can then be used to enable or disable the actual menu options as in the mockup.
To simplify things:
- The user has to pick one option from the first row, and then the one below, and so on.
- If an option in an earlier row is selected, the options selected after that one are removed.
- Options that cannot result in a valid combination need to be disabled, ie. the corresponding place in
menu_toggles
must befalse
.
Examples
Using the menu
and variants
above.
No options selected
options = []
menu_toggles = [
[true, true, true, true],
[false, false, false],
[false, false]
]
One option selected
options = [36]
menu_toggles = [
[true, true, true, true],
[true, false, false],
[false, false]
]
Two options selected
options = [36, 47]
menu_toggles = [
[true, true, true, true],
[true, false, false],
[true, false]
]
Two options selected (other)
options = [41, 47]
menu_toggles = [
[true, true, true, true],
[true, false, false],
[false, true]
]
Current approach (as of this writing)
My current solution looks like this:
const available_variants = variants
.filter(v => {
if (!v) return false;
if (!options.every((o, i) => o === v[i])) return false;
return true;
});
const menu_toggles = [
...menu
.slice(0, options.length)
.map(l => l
.map(() => true)),
...menu
.slice(options.length)
.map((z, i) => z
.map((value, j) => available_variants
.some(v => v[i + options.length] === value)))
];
In this one, I first make a list of combinations that make sense for the "next" row to select, but obviously this only disables menu options from that row down.
4
Answers
The code below provides the intended behavior.
I made a super basic toy example that shows you one way to approach it. In particular, I think you’re interested in the
disableButtons
function.I don’t know what system to render/update your buttons you have. Here an example where it computes a whitelist based on
variants
and the currentoptions
and then toggles thedisabled
property of the buttons/checkboxes accordingly.You could build a tree of possibilities and enable the menu row and disable the row after the selected level.