downshift icon indicating copy to clipboard operation
downshift copied to clipboard

setHighlightedIndex not working from onInputValueChange

Open allison-palum opened this issue 4 years ago • 3 comments

  • downshift version: 6.1.3
  • node version: 14.15.1
  • npm version: 6.13.7

Relevant code or config

/**
* find the index of the item that most closely 
* matches the users input 
*/
const findHighlightedIndex = (inputValue) => {
   if (!inputValue) {
      return -1;
   }

   const searchValue = inputValue.toLowerCase();

   for (let i = 0; i < items.length; i++) {
      const item = itemToString(items[i]).toLowerCase();
      if (item.indexOf(searchValue) !== -1) {
         return i;
      }
   }

   return -1;
};


/**
* manually set the current highlighted item as Downshift understands it based 
* on the users input
*/
const handleOnInputValueChange = (inputValue, { setHighlightedIndex }) => {
   setHighlightedIndex(findHighlightedIndex(inputValue));
};

...
<Downshift
   onChange={handleOnChange}
   onInputValueChange={handleOnInputValueChange} // <----
   itemToString={itemToString}
   itemToElement={itemToElement}
   defaultSelectedItem={defaultSelectedItem}
>
...

What you did: I am trying to manually set the highlightedIndex via setHighlightedIndex to the item that most resembles the inputValue To do this, I am calling a function called handleOnInputValueChange when onInputValueChange is triggered. There, I find the index I'd like to be highlighted and I send it to the setHighlightedIndex function

What happened: The handleOnInputValueChange is being called, and the correct index value is being returned from findHighlightedIndex. However, the highlighted item is not changing when it's respective index is sent to setHighlightedIndex

Note: The reason I am using <Downshift/> vs. the useComboBox hook is because I need access to getRootProps seeing as I am using a custom wrapper...let me know if this is amendable

allison-palum avatar Jun 03 '21 15:06 allison-palum

Hi! The setHighlightedIndex function should work. If you can spend some time debugging this great, I can help you submit a fix, if any.

Though, in your current scenario, I'd use stateReducer. Just do the same search as you are doing now in the state reducer function and return the default state from Downshift along with the custom highlightedIndex. I think it's more elegant. There are many usage examples of state reducer in our github/codesandbox repo/docsite, here is one. https://www.downshift-js.com/use-combobox#state-reducer

But if you can investigate the problem you are facing then that's even better for us. Also you could consider creating a codesandbox reproducing this bug. Thanks!

silviuaavram avatar Jun 03 '21 16:06 silviuaavram

Thank you for the speedy reply. Let me give stateReducer a shot!

allison-palum avatar Jun 03 '21 17:06 allison-palum

Hello! I was able to get the highlightIndex set correctly by using the stateReducer.

However, I am running into another issue. The arrowDown and arrowUp functionality that updates the highlighted index does not work when I initially open the menu, but does once I've opened and closed the menu once.

  • on initial render, if I open the menu then click the up and down arrows, nothing happens
  • on initial render, if I open the menu, close it and then open it again, the arrows work as suspected

please see my stateReducer below....

const stateReducer = (state, changes) => {
   setTopItems(changes.selectedItems);
   switch (changes.type) {
      /**
      * ensure that the menu stays open when item is selected
      * and that selected item is highlighted
      */
      case Downshift.stateChangeTypes.keyDownEnter:
      case Downshift.stateChangeTypes.clickItem:
         return {
            ...changes,
	    isOpen: true,
            highlightedIndex: state.highlightedIndex
         }
         /**
         * close menu when escape key pressed
         */
         case Downshift.stateChangeTypes.keyDownEscape:
            return {
               ...changes,
               isOpen: false
            }
         /**
         * otherwise, do the default Downshift-y things
         */
         default:
            return changes
   }
}

allison-palum avatar Jun 03 '21 22:06 allison-palum

setTopItems(changes.selectedItems); should not be in the reducer, as it's meant to be a pure function.

Otherwise I see nothing wrong with the reducer.

silviuaavram avatar Dec 17 '22 14:12 silviuaavram

FYI to maintainers – I also have this issue. setHighlightedIndex doesn't seem to work on this callback.

drewlustro avatar Feb 26 '23 04:02 drewlustro