TLDR;
You can use the modulo operator in conjunction with the length of the array. This requires you to set you position after every change.
handleOverflow(options, chosen) {
return (options.length + chosen) % options.length
}
Recently, I was working on a search input with an autocomplete feature. One of the requirements was that users should be able to cycle through the options by pressing arrow keys. Additionally, if you were at the last item and pressed down
it should jump to the first item in the list. Similarly, if you were at the first element and pressed up
it should jump to the last item.
First Solution
The Mental Model
- I have an array of options
- I have a numerical value to access one element of that array, the index
- In order to get the next element I increase the index.
- In order to get the previous element I decrease the index.
- If the index gets below
0
I need to jump to the end - If the index gets bigger than the index of the last element, I need to jump to first element.
Solution
handleOverflow(options, chosen) {
let next = chosen;
if (next > options.length - 1) {
next = min;
}
if (next < 0) {
next = max;
}
return next;
}
What I did not like about the implementation
- It is verbose
- I have to reset a value inside of the function
'Improving' the solution
What basically happens is that I need to access an element in a list with a known size. So basically, I only need to worry about the size of the array and the position I am at.
So, if I am at position 5 (meaning the 6th element) in an array with 6 elements and I want to go to the next element I go to index 6. Unfortunately, that does not exist so I go back to the start which is at index 0. I know that 6 % 6
equals 0
. Hence, accessing the array by index % array.length
would work for positive numbers.
With negative numbers, that does not work unfortunately as -1 % array.length
equals -1
so even by removing the -
I would land at the first element, not the last. This forces me to add the length of the array to the result of the modulo operation and BAM, we have the solution:
handleOverflow(options, chosen) {
return (options.length + chosen) % options.length
}
What do you think about this solution?
Is it better or worse than the first?
How would you handle this problem?
Best and Happy Holidays!
Top comments (0)