0

This is in reference to the code at this fiddle: http://jsfiddle.net/x8whpx09/17/

I am trying to create a search box with a result list that pops up when the user enters something. The problem I am encountering is when the user clicks anywhere other than the input element the search result list will close. I have a focusout event attached to the parent DIV, but even if I attach it to the input I get the same behavior. What I want is for the user to be able to select the scroll bar on the list and not have the list disappear. If they click outside of the input, or the list then the list should close.

Right now it closes no matter where they click unless it is in the input.

EDIT: The performSearch function body is wrapped in an AJAX request.

SOLUTION: I finally figured out what is happening. You need to bind to the mousedown event and return false in order to allow selecting the scrollbar in the dropdown. This question finally gave me the solution.

$target.on('mousedown',function (event) {
            return false;
        });

Here is the code at the fiddle:

var search = {
  closing: null,
  performSearch: function(elem, e) {
    var $this = $(elem);
    var $target = $('#search-results');
    if ($target.length === 0) {
      $target = $('<div id="search-results" class="sb-list"></div>');
      $target.insertAfter($this);
      var p = $this.position();
      $target.css('top', (p.top + $this.height() + 15) + 'px');
      $target.css('width', ($this.width() + p.left + 10) + 'px');
      $target.css('width', ($this.width() + 25) + 'px');
      $target.css('left', (p.left) + 'px');
      $target.slideDown('fast', function() {
        $target.css('overflow', 'auto');
      });
      $target.on('mouseover', '.sb-row', function() {
        $(elem).addClass('sb-active');
        $('.sb-active').removeClass('sb-active');
      });
      $target.on('click', '.sb-row', search.click);
      //$target.parent().on('focusin focusout', search.listFocus);
    } else {
      $target.empty();
      $target.slideDown('fast', function() {
        $target.css('overflow', 'auto');
      });
    }

    for (i = 0; i < 40; i++) {
      var html = [];
      html.push('<div class="sb-row' + (i == 0 ? ' sb-active' : '') + '">');
      html.push('<a href="#">test result' + i + '</a>');
      html.push('</div>');

      var $out = $(html.join(''));
      $target.append($out);
    }
  },
  delayClose: function(e) {
    console.log('delayClose');
    var self = this;
    console.log('results focused: ' + $('#search-results').is(':focus'));
    console.log('div focused: ' + $('#parent').is(':focus'));
    search.closing = window.setTimeout(function() {
      search.close.apply(self, arguments);
    }, 1000);
  },
  listFocus: function(e) {
    console.log(e.type);
    var self = this;
    window.clearTimeout(search.closing);
  },
  click: function(e) {
    console.log('clicked');
  },
  close: function(e) {
    console.log('closing');
    window.clearTimeout(search.closing);
    var $this = $(this);
    $('#search-results').slideUp('fast');
  }
};

$(document).ready(function() {
  $searchBox = $('#search');
  $searchBox.on('focus', function(e) {
    this.value = '';
    this.select();
    e.stopPropagation();
    return false;
  });
  $searchBox.on('keyup', function(e) {
    search.performSearch($searchBox[0], e);
  });
  $searchBox.parent().on('focusout', search.delayClose);
});
.sb-list {
  position: absolute;
  width: 250px;
  top: 0;
  left: 0;
  height: 300px;
  background: #FAFAFA;
  border: solid 1px #999;
  border-top: none;
  display: none;
  overflow: auto;
  z-index: 92592;
  -webkit-box-shadow: 0 2px 2px #999999;
  -moz-box-shadow: 0 2px 2px #999999;
  -ms-box-shadow: 0 2px 2px #999999;
  box-shadow: 0 2px 2px #999999;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="parent">
  <input type="text" id="search" />
</div>
Community
  • 1
  • 1
coryrwest
  • 700
  • 1
  • 8
  • 23
  • How about an [mcve](http://stackoverflow.com/help/mcve)? – Teemu Feb 11 '15 at 20:55
  • The JSFiddle snippet you provided does not have this issue (dropdown won't disappear), but also does not automatically close at all. Are you looking for functionality that will make the dropdown close when clicked outside? Or one that will keep the input focused when clicking on the dropdown? – John Weisz Feb 11 '15 at 21:07
  • @JánosWeisz I want the dropdown to close when you click `outside` of it or the input, but not when you click `inside` it or the input. – coryrwest Feb 11 '15 at 21:13

1 Answers1

0

You have some malfunctioning code here and multiple things to fix. If you inspect #search (the input box), you'll see that search results appear additively for every character entered. That is, you end up with multiple id="search-results" elements.

A very easy oneline solution for this single error is to add $('#search-results').remove(); to your performSearch handler function:

performSearch: function (elem, e) {
    $('#search-results').remove();
    // ...
}

I have created an updated JSFiddle to demonstrate its functioning and the additional inconveniences and errors this introduces, one of them being the lack of correct event handling when you click the #search-results dropdown itself.

I suggest you try and track the source of errors in the code of your search using Developer Tools or a Javascript debugger, because there are numerous sections in your code that would need either fixing, or rethinking; too much for a single answer.

John Weisz
  • 30,137
  • 13
  • 89
  • 132