1

I am working on a search component with auto-complete functionality and I am running into some strange behavior. The component consists of an input (SearchInput) and a list of type-ahead results (SearchResultWrapper).

Clicking on a type-ahead result should populate the SearchInput field with the selected result and hide the type-ahead results. Losing focus on the field should also hide the results.

Sample code can be found here: https://jsfiddle.net/chez/h22qfx45/.

The issue comes when you comment in the closeResults function which is responsible for changing the state of the component to hide the type-ahead results. When this code is activated, the onClick handler for the SearchResult is no longer picked up by React.

There is obviously a fundamental concept I am missing here. Is React disconnecting its event listeners from the SearchResult component since it is hidden?

Nitax
  • 450
  • 1
  • 4
  • 18
  • You have a race-condition. Change your `closeResults` to `setTimeout(() => this.setState({resultsOpen: false}), 200);` to observe it. I'm guessing you're hiding the element before the click is registered (remember, the browser will remove focus before it can trigger a click event). I've no time to look further at it right now but maybe it helps. – ivarni Jul 25 '16 at 16:17
  • It would be nice if you could post the part of the code that is most confusing or you think is most important. – HoldOffHunger Sep 13 '17 at 19:23

2 Answers2

5

There's a thing in JS : onBlur is called before onClick.

To solve it, you just need to replace onClick by onMouseDown.

Here's the code : https://jsfiddle.net/h22qfx45/5/

Source : onclick() and onblur() ordering issue

Community
  • 1
  • 1
F. Kauder
  • 879
  • 5
  • 9
  • 1
    Not really an issue with React AFAIK, that's just the order things are happening in the browser. React just happens to react fast enough (harr) that it matters :) – ivarni Jul 25 '16 at 16:21
  • I replace _issue_ by _thing_. Thanks for the informations :) – F. Kauder Jul 25 '16 at 16:23
  • 1
    It's a javascript *thing* really. – Chris Jul 25 '16 at 16:25
  • 1
    I found a codepen that illustrates this. Notice what happens when you focus the input before firing the click. https://codepen.io/mudassir0909/pen/eIHqB. Really, it's a DOM thing ;) – ivarni Jul 25 '16 at 16:26
  • Thanks for the quick answer. My only concern is that the [DOM Level 3 Events](https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click) spec states: _For maximum accessibility, content authors are encouraged to use the click event type when defining activation behavior for custom controls, rather than other pointing-device event types such as mousedown or mouseup, which are more device-specific_. However, using 'onMouseDown' seems to work in practice... – Nitax Jul 26 '16 at 13:17
1

Forget about the onBlur event. onBlur is not when you mean to hide your content. You mean to hide your content once a selection has been made. So, I would propose that you completely remove the closeResults() method as well as the onBlur event. From there you will want to change your handleSearchResultClick() method to include changing the visibility state of the results.

I have an updated Fiddle that does what you are looking for here.

In short: Remove these:

onBlur={this.closeResults}

closeResults() {
//this.setState({resultsOpen: false});
},

and change

handleSearchResultClick(event) {
    var selectedResult = event.target.innerText;
    this.setState({searchString: selectedResult});
},

to

handleSearchResultClick(event) {
    var selectedResult = event.target.innerText;
    this.setState({searchString: selectedResult, resultsOpen: false});
},
lkg
  • 876
  • 4
  • 10
  • So the example above is one field that composes a larger form. It is possible that the user will move focus to another field without making a selection. `onBlur` seemed like a good trigger to close the results that did not depend on cross-component communication... – Nitax Jul 26 '16 at 13:08