GothamCityRises
GothamCityRises

Reputation: 2102

SemanticUI Search - Dropdown selection does not populate input

I'm building an input component using Semantic UI React. I want it to open the dropdown whenever in focus, instead of the default behavior, which is to show results when the user changes the search string. I'm using the props available on their website here.

Here's some of my relevant code:

constructor(props) {
  super(props);
  this.handleResultSelect = this.handleResultSelect.bind(this);
  this.handleFocusSearch = this.handleFocusSearch.bind(this);
  this.handleBlurSearch = this.handleBlurSearch.bind(this);
  this.state = ({
    results: [{
      "title": "Roob, Cummerata and Watsica"
    },
    {
      "title": "Stanton, Kessler and Walsh"
    },
    {
      "title": "Boyle, Schuppe and Renner"
    }],
    value: '',
    open: false,
  });
}

handleBlurSearch () {
  this.setState({ 
    open: false,
    focused: false,
  });
}

handleFocusSearch () {
  this.setState({ 
    open: true,
    focused: true,
  });
}

handleResultSelect(e, {result}) {
  this.setState({ value: result.title });
}

render() {
  var searchProps = {
    input: <input className='custom-form-field' placeholder={this.props.placeholder}/>,
    open: this.state.open,
    onFocus: this.handleFocusSearch,
    onBlur: this.handleBlurSearch,
    results: this.state.results,
    onResultSelect: this.handleResultSelect,
    value: this.state.value,
  };

  return ( 
    <SemanticUI.Search {...searchProps} />
  );
}

However, on selecting a result, the result title value is not set in the input value. Moreover, on debugging, I found that handleResultSelect was not even being called.

My first guess is that onBlur causes the results dropdown to close, and the result select event is ignored. I'm not sure though; I'm very new to React and Semantic.

Any help figuring this out would be welcome.

Upvotes: 3

Views: 2049

Answers (3)

GothamCityRises
GothamCityRises

Reputation: 2102

I really appreciate R. Wright's answer, but the 200ms delay that was being added to the dropdown blur was not up to UX standards. So I dug a little deeper into javascript's blur, and found it has a relatedTarget attribute, which can be used to see what element the click was made on.

Note that, this somehow only works on DOM elements with the tabindex attribute, so I also had to modify Semantic Search's result renderer to make each result have an attribute tabindex=0. Also, it's possible to override the default focus CSS that is applied to elements with tabindex.

Using that, I edited handleBlur to set open: true if _.contains(event.relatedTarget.classList, 'title').

Here's some of my relevant code:

constructor(props) {
  super(props);
  this.handleResultSelect = this.handleResultSelect.bind(this);
  this.handleFocusSearch = this.handleFocusSearch.bind(this);
  this.handleBlurSearch = this.handleBlurSearch.bind(this);
  this.state = ({
    results: [{
      "title": "Roob, Cummerata and Watsica"
    },
    {
      "title": "Stanton, Kessler and Walsh"
    },
    {
      "title": "Boyle, Schuppe and Renner"
    }],
    value: '',
    open: false,
  });
}

handleBlurSearch (event) {
  let open = _.contains(event.relatedTarget.classList, 'title');
  this.setState({ 
    open: open,
    focused: false,
  });
}

handleFocusSearch () {
  this.setState({ 
    open: true,
    focused: true,
  });
}

handleResultSelect(e, {result}) {
  this.setState({ value: result.title, open: false });
}

render() {
  var searchProps = {
    input: <input className='custom-form-field' placeholder={this.props.placeholder}/>,
    open: this.state.open,
    onFocus: this.handleFocusSearch,
    onBlur: this.handleBlurSearch,
    results: this.state.results,
    onResultSelect: this.handleResultSelect,
  };

  return ( 
    <SemanticUI.Search {...searchProps} />
  );
}

Upvotes: 1

R. Wright
R. Wright

Reputation: 1035

Another option, look at the Dropdown component. The Search Selection example in the Dropdown may show the behavior that you're trying to create.

https://react.semantic-ui.com/modules/dropdown/#types-search-selection

Upvotes: 0

R. Wright
R. Wright

Reputation: 1035

Try adding the value prop to the searchProps. Also, the onBlur event and onResultSelect are conflicting with each other, so I added a delay with the lodash.debounce function.

So, something like this

class SearchExampe extends React.Component {
  constructor(props) {
    super(props);
    this.handleResultSelect = this.handleResultSelect.bind(this);
    this.handleFocusSearch = this.handleFocusSearch.bind(this);
    this.handleBlurSearch = this.handleBlurSearch.bind(this);
    this.handleSearchChange = this.handleSearchChange.bind(this);

    this.state = {
      results: [
        {
          title: "Roob, Cummerata and Watsica"
        },
        {
          title: "Stanton, Kessler and Walsh"
        },
        {
          title: "Boyle, Schuppe and Renner"
        }
      ],
      value: " ",
      open: true
    };
  }

  handleSearchChange(e) {
    this.setState({ value: e.target.value });
  }

  handleBlurSearch() {
    this.setState({
      open: false,
      focused: false
    });
  }

  handleFocusSearch() {
    this.setState({
      open: true,
      focused: true
    });
  }

  handleResultSelect(e) {
    this.setState({ value: e.target.value, open: false });
  }

  render() {
    var searchProps = {
      input: <input className="custom-form-field" onChange={this.handleSearchChange} placeholder="placeholder" />,
      open: this.state.open,
      onFocus: this.handleFocusSearch,
      onBlur: _.debounce(this.handleBlurSearch, 100, {}),
      results: this.state.results,
      onResultSelect: this.handleResultSelect,
      value: this.state.value
    };

    return <Search {...searchProps} />;
  }
}

Upvotes: 3

Related Questions