Reputation: 2102
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
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
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
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