Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to display all options in react bootstrap typeahead menu with existing selection

I want the entire menulist to show onFocus instead of only the selected element unlike the pic given below.

enter image description here

<Typeahead
  labelKey="label"
  options={options}
  placeholder="Search.."
  onFocus={(e)=>this.onFocus(e)}
  onKeyDown={()=>this.onChange()}
  ref={(typeahead) => this.typeahead = typeahead}
  selected={this.props.single}
  renderMenuItemChildren={(option) => (
    <div onClick={(e)=>this.handleClick(e)} value={option.label}>
      {option.label}
    </div> 
  )}
/>
like image 348
Srijita Avatar asked May 15 '18 11:05

Srijita


2 Answers

From similar question and answer:

The filterBy prop can take a custom function, allowing you to filter results however you want.

Example:

<Typeahead
  filterBy={(option, props) => {
    if (props.selected.length) {
      // Display all the options if there's a selection.
      return true;
    }
    // Otherwise filter on some criteria.
    return option.label.toLowerCase().indexOf(props.text.toLowerCase()) !== -1;
  }}
  labelKey="label"
  options={options}
  placeholder="Search.."
  onFocus={(e)=>this.onFocus(e)}
  onKeyDown={()=>this.onChange()}
  ref={(typeahead) => this.typeahead = typeahead}
  selected={this.props.single}
  renderMenuItemChildren={(option) => (
    <div onClick={(e)=>this.handleClick(e)} value={option.label}>
      {option.label}
    </div> 
  )}
/>

Edit: The example above assumes that the options array passed to the typeahead contains options of type { label: string }. For a different labelKey or an array of strings, the filtering would need to be updated accordingly

// options: Array<{ name: string }>
return option.name.toLowerCase().indexOf(props.text.toLowerCase()) !== -1

// options: Array<string>
return option.toLowerCase().indexOf(props.text.toLowerCase()) !== -1
like image 90
ericgio Avatar answered Oct 10 '22 17:10

ericgio


@ericgio's answer didn't work for me because react-bootstrap-typeahead no longer uses the name field. I used it though to craft my own Typeahead class below with a number of custom options, including showing all options when clicked. It falls back to the original behavior as well when multiple is set to true.

import { Typeahead as ReactBootstrapTypeahead } from "react-bootstrap-typeahead";
import defaultFilterBy from "react-bootstrap-typeahead/lib/utils/defaultFilterBy";
import React from "react";

/**
 * This class is responsible for setting a few sensible defaults on the typeahead object.
 */
export default class Typeahead extends React.Component {
  constructor(props) {
    super(props);
  }

  /**
   * This shows all of the values when you click into the typeahead, even if something is selected.  See more
   * here: https://stackoverflow.com/a/50376581/491553
   */
  static showAllOnClick(option, props) {
    if (props.multiple) {
      const newProps = {...props, filterBy: ["label"]};
      return defaultFilterBy(option, newProps);
    } else {

      if (props.selected && props.selected.length) {
        // Display all the options if there's a selection.
        return true;
      }

      // Otherwise filter on some criteria.
      return option.label && option.label.toLowerCase().indexOf(props.text.toLowerCase()) !== -1;
    }
  }

  render() {
    return <ReactBootstrapTypeahead {...this.props} />;
  }
}

Typeahead.defaultProps = {
  filterBy: Typeahead.showAllOnClick, // Show all of the results even if something is selected
  positionFixed: true, // Display the typeahead above scrollbars
  inputProps: {autocomplete: "off"}, // Turn off autocomplete in Chrome
};
like image 2
Ryan Shillington Avatar answered Oct 10 '22 15:10

Ryan Shillington