React-bootstrap-typeahead: Auto-highlight only option

Created on 8 Sep 2016  路  11Comments  路  Source: ericgio/react-bootstrap-typeahead

It would be handy to select the first value in the dropdown on pressing ENTER even if that value is not selected

  case _keyCode.RETURN:
    // Prevent submitting forms.
    e.preventDefault();

    if (this.state.showMenu) {
      var selected = options[activeIndex] || options[0];
      selected && this._handleAddOption(selected);
    }
    break;
feature request

Most helpful comment

Thanks @daschi, that was very helpful!
Here's a similar implementation that doesn't require jQuery.
````
fixTypeahead() {
const {container} = this;
if (!container) return;

const input = container.querySelector('input');
if (input.onkeydown) return; // don't need to set this up again

input.onkeydown = event => {
  if (event.keyCode !== 13) return;
  const items = container.querySelectorAll('.bootstrap-typeahead-menu > li');
  if (items.length === 1) items[0].querySelector('a').click();
};

}
``` I call this fromcomponentDidMountandcomponentDidUpdate`.

I wrap my Typeahead in a div like this:
````

...

And here is saveTypeahead:
const saveTypeahead = c => this.container = c;
````

All 11 comments

This is probably not something I'd want to add, for a couple reasons.

First, in the single-selection case, this functionality essentially already exists via hinting and pressing either tab or the right arrow key to autocomplete.

Second, I don't think it's common or expected behavior in a typeahead. Typically, hitting 'enter' when partial text has been typed would trigger an operation based on that text alone. For example, when I do the following Google search, hitting 'enter' will search for 'where' not 'where am i':

image

Furthermore, this component is based on Twitter's Typeahead.js, which is in turn based on their own search functionality and behavior. Given that the functionality you describe is not reflected in the library, I take it as a further sign that it's not canonical behavior.

The one case where I could see this potentially being valid behavior is if the allowNew prop is set, since any text entered is implicitly a valid entry. In any case, I'll keep this issue open for now to see if anyone else comments with use cases or opinions.

Fair point, it should not be part of the standard behaviour.
Maybe exposing the event handling functions would make it easier for users of the component to implement custom behavior ? In my use case I replaced the whole _handleKeydown function:
typeahead.getInstance()._handleKeydown = function() {...}.
But that is accessing private internals of react-bootstrap-typeahead :-)

I'm starting to look at ways I might pull some of these behaviors out into higher-order components to separate them from the rendering piece. This could potentially provide a way to expose a public API for customizing behaviors. Probably not something that's coming in the immediate future, though.

What are your thoughts on whether it's canonical behavior to hit the ENTER key to select a value when it is the last option in the list? Would it be possible to implement that with the current api?

It seems reasonable to auto-highlight a selection if it's the only option, which would then allow the user to hit enter to select it.

In case it's helpful to anyone or if anyone has a better idea, here's how we implemented that:

$('.bootstrap-typeahead-input-main').keydown(function(event) {
      let menuLength = $('.bootstrap-typeahead-menu > li').length
      if(event.keyCode == 13 && menuLength == 1) {
        $('.bootstrap-typeahead-menu li:first-child > a').first()[0].click()
      }
})

+1 for that feature. This is quite common functionality for autocomplete controls. Since there is no customizable autocomplete tokenizer I found yet, I think that would be nice to have some boolean property 'autocomplete' which enables first option selection on enter pressed. You can find similar behavior when selecting users from predefined list. For example while sharing some note in https://keep.google.com.

Thanks @daschi, that was very helpful!
Here's a similar implementation that doesn't require jQuery.
````
fixTypeahead() {
const {container} = this;
if (!container) return;

const input = container.querySelector('input');
if (input.onkeydown) return; // don't need to set this up again

input.onkeydown = event => {
  if (event.keyCode !== 13) return;
  const items = container.querySelectorAll('.bootstrap-typeahead-menu > li');
  if (items.length === 1) items[0].querySelector('a').click();
};

}
``` I call this fromcomponentDidMountandcomponentDidUpdate`.

I wrap my Typeahead in a div like this:
````

...

And here is saveTypeahead:
const saveTypeahead = c => this.container = c;
````

@mvolkmann This is great. I was able to just make a <FixedTypeahead /> component which does this work! This should be in the docs or a FAQ somewhere.

This is how I solved it for a Typeahead that has multiple: true and allowNew: true. It is not tested for any other combination of these props and will with a high chance break.

class TokenBasedSearchBar extends Component {

    constructor(props) {
        super(props);
        this.handlOnInputChange = this.handlOnInputChange.bind(this);
        this.state = { textValue: '' };
    }

    componentDidUpdate(_, prevState) {
        if (this.state.textValue !== prevState.textValue) {
            const instance = this.typeahead.getInstance();
            const { initialItem } = instance.state;
            instance.setState({ activeIndex: 0, activeItem: initialItem });
        }
    }

    handlOnInputChange(text) {
        this.setState({ textValue: text });
    }

    render() {
        const { tags, onChange, selected, labelKey, minLength, searchFor, autoFocus } = this.props;

        return (
            <Typeahead
              ref={(c) => { this.typeahead = c; } }
              onChange={onChange}
              options={tags}
              labelKey={labelKey}
              multiple
              allowNew
              selected={selected}
              renderToken={renderToken}
              renderMenu={renderMenu}
              onInputChange={this.handlOnInputChange}
            />
        );
    }
}

One thing I like to add. It is mandatory to put the handling of the ativeIdex/activeItem into the componentDidUpdate hook, cause the onInputChange gets fired before the result processing takes place. I am not sure about race-conditions, but I heavily tested it and I had no problems so far.

highlightOnlyResult prop added in v2.0.0-alpha.1

Was this page helpful?
0 / 5 - 0 ratings

Related issues

orekav picture orekav  路  5Comments

abdulrahman-khankan picture abdulrahman-khankan  路  6Comments

yedyharova picture yedyharova  路  9Comments

mflauer picture mflauer  路  4Comments

gilm123 picture gilm123  路  10Comments