0

Below is my script. It's a autosuggestion search script. The problem is that it penetrates the server with a huge amount of requests (it sends a request after each inserted character).

I need to change the script so that it waits 2 seconds after user has finished typing (and has inserted at least 3 characters) and only then sends request to the php file.

(function($){
$.fn.fsearch = function(){
  var $searchInput = $(this);
  $searchInput.after('<div id="divResult"></div>');
  $resultDiv = $('#divResult');
  $searchInput.focus();
  $searchInput.addClass('searchi');
  $resultDiv.html("<ul></ul><div id='search-footer' class='searchf'></div>");
  $searchInput.keyup(function(e) {
  var q=$(this).val();
if(q.length>2&&q.length<30){ 
      var current_index = $('.selected').index(),
      $options = $resultDiv.find('.option'),
      items_total = $options.length;
      $resultDiv.fadeIn();
      $resultDiv.find('#search-footer').html("<img src='img/loader.gif' alt='Searching...'/>");

      $.getJSON("/search.php",{searchword: q},function(jsonResult) { 
        var str='';
        for(var i=0; i<jsonResult.length;i++)
          {
            str += '<li id=' + jsonResult[i].uid + ' class="option"><img class="profile_image" src="photos/'+jsonResult[i].media+'" alt="'+jsonResult[i].username+'"/><span class="name">' + jsonResult[i].username + '</span><br/>'+jsonResult[i].country+'</li>';
          }
          $resultDiv.find('ul').empty().prepend(str);
          $resultDiv.find('div#search-footer').text(jsonResult.length + " results found...");
          $resultDiv.find('ul li').first().addClass('selected');
      }); 

        $resultDiv.find('ul li').live('mouseover',function(e){
        current_index = $resultDiv.find('ul li').index(this);
        $options = $resultDiv.find('.option');
        change_selection($options,current_index);
      });


      function change_selection($options,current_index){
        $options.removeClass('selected');
        $options.eq(current_index).addClass('selected');
        }

    } else{

      $resultDiv.hide();
    }
  });    

  jQuery(document).live("click", function(e) { 
    var $clicked = $(e.target);
    if ($clicked.hasClass("searchi") || $clicked.hasClass("searchf")){
    }
    else{
      $resultDiv.fadeOut(); 
    }
  });

  $searchInput.click(function(){
    var q=$(this).val();
    if(q.length>2&&q.length<30) { 
      $resultDiv.fadeIn();
    }
  });

  $resultDiv.find('li').live("click",function(e){ 
    var id = $(this).attr('id');
    var name = ($(this).find('.name').text());
    $searchInput.val(name);
  });

  };
})(jQuery);

After reading this question I added the following solution to my script:

var timer;
var x;

$(".some-input").keyup(function () {
    if (x) { x.abort() } // If there is an existing XHR, abort it.
    clearTimeout(timer); // Clear the timer so we don't end up with dupes.
    timer = setTimeout(function() { // assign timer a new timeout 
        x = $.getJSON(...); // run ajax request and store in x variable (so we can cancel)
    }, 2000); // 2000ms delay, tweak for faster/slower
});

unfortunately, it does not work:

TypeError: e.nodeName is undefined jquery-1.11.0.min.js:4:9004
Community
  • 1
  • 1
Gigante
  • 327
  • 2
  • 11
  • 2
    Which line throws this error? Just be aware inside setTimeout callback, the default context is window object. Maybe try: `timer = setTimeout(function() { // assign timer a new timeout x = $.getJSON(...); // run ajax request and store in x variable (so we can cancel) }.bind(this), 2000);` But i'm still not sure what you are setting in timeout callback? Only ajax request or what? And please consider to upgrade your jQuery version, avoiding to use `live()` method – A. Wolff Jan 15 '16 at 13:07
  • One potential issue I see is `if (x) { x.abort() }` - should it be `if (x) { x.abort(); x = null; }` ... though, not the problem at hand I don't think – Jaromanda X Jan 15 '16 at 13:27

0 Answers0