Search code examples
javascriptreactjsreactivesearch

ReactJS - ReactiveSearch - Custom event on suggestion selection


I am building an autocomplete component to search current users and add them to a team. The search works fine except I need to customize a couple things that I can't figure out how to do.

First, this component is modeled after GitHub's invite user modal. You can start typing to search for a current user and it populates any results it finds. However, if it doesn't find any results it only shows one item to invite that user via email. How can I edit the full state of the result list for a DataSearch component? All I can see is to edit the content of each suggestion via the onSuggestion prop. I need to be able to say, "If there are zero results, display this."

Second, when a suggestion from the autocomplete result list is selected, I need to be able to reset the search box because I am populating a list that the user can see. Right now, the search box is populated with the value of the suggestion. So, I am populating the list below of selected results just fine; but, I still need to be able to reset the search box when that result is selected.

Help????


Solution

  • CodeSandbox link

    For the first part of the problem, you can use the prop onNoResults on any of the results components to render custom JSX when no results are found. From the docs:

    onNoResults String or JSX [optional]

    show custom message or component when no results founds.

    <ResultList
        ...
        // custom JSX when no results are found
        onNoResults={
            <section>
                <input />
                <button>Add</button>
            </section>
        }
    />
    

    For the second part of the problem, there are two ways IMO you may approach this.

    1. Using a ReactiveComponent which lets you create a custom ReactiveSearch component.
    2. Using customQuery

    I'll explain how to approach this using customQuery but it might be better to create a custom component depending on which approach suits your needs best.

    In the example I've shared my DataSearch looks like this:

    <DataSearch
        title="DataSearch"
        dataField={["original_title", "original_title.search"]}
        categoryField="authors.raw"
        componentId="BookSensor"
        customQuery={this.customQuery}
        defaultSelected={this.state.value}
        onValueSelected={this.updateState}
    />
    

    The reason for using a customQuery is to get full control of which query gets applied to retrieve the results. ReactiveSearch is designed to work reactively. When a value is set into the DataSearch, the ResultList would react to this change. Having a customQuery lets us control which query is fired for this change. Also I'm keeping the value of DataSearch in the state so I can clear it up when the query gets fired. Here's what I'm using in the example:

    customQuery = (value, props) => {
        // find the current query using defaultQuery from DataSearch
        const currentQuery = DataSearch.defaultQuery(value, props);
        // clear the value in component's state
        this.setState({
          value: ""
        });
        if (value.length) {
          // store this query
          this.prevQuery = currentQuery;
          return currentQuery;
        }
        // if the value is empty, that is it was cleared, return the previous query instead
        return this.prevQuery;
      };
    

    So whenever the value is cleared, I just return the previous query so the result list shows the correct results for the previous query (before the value was cleared).

    Also in order to control the value of DataSearch from my component I'm using the defaultSelected and onValueSelected props. They work quite similar to how you would create a controlled component in react. Docs

    Again, it might be better to create a custom component using ReactiveComponent if this approach sounds complicated to customize this flow.

    Demo for this answer using customQuery