react-bootstrap-typeahead

Multiple datasets grouping with react-bootstrap-typeahead


I am trying to replicate a search field using old jQuery typeahead with react-bootstrap-typeahead. It queries uses multiple async data sources, and display the result grouped by the return of such sources.

multiple sources displayed

For instance, as seen on the image, by typing the letter "b" it queries an address database as well as the previously searched values by user (saved on React store) and display results grouped by each database. If a result is empty for a given database, it is not shown, as the next example:

single source displayed

According to this closed issue on the project it is possible to query multiple databases making multiple queries on the onSearch function. But is it possible to group the results like on the above example?


Solution

  • Yes, it's possible to group the search results in the way you describe. You can use the renderMenu prop to group the results by data source and render a menu header to denote each source.

    Here's an adaptation from the live examples:

    const renderMenu = (results, menuProps, props) => {
      let index = 0;
    
      // Group the results by the "region" key in each option.
      const regions = groupBy(results, 'region');
      const items = Object.keys(regions)
        .sort()
        .map((region) => {
          return (
            <React.Fragment key={region}>
              {index !== 0 && <Menu.Divider />}
              <Menu.Header>{region}</Menu.Header>
              {regions[region].map((option) => {
                const item = (
                  <MenuItem key={option.label} option={option} position={index}>
                    <Highlighter search={props.text}>{option.label}</Highlighter>
                  </MenuItem>
                );
    
                index += 1;
                return item;
              })}
            </React.Fragment>
          );
        });
    
      return <Menu {...menuProps}>{items}</Menu>;
    };
    
    const GroupedResults = () => {
      return (
        <Typeahead
          id="grouped-results"
          options={options}
          placeholder="Choose a state..."
          renderMenu={renderMenu}
        />
      );
    };
    

    Here's the working sandbox.

    As far as the data source is concerned, note that the typeahead component is essentially agnostic about that; it is simply filtering the array passed into the options prop, which can come from anywhere, or even multiple places.