0

i am trying to create a search using multiple jquery functions

i have created this code and functions:

$(document).ready(function() {
    var timer = null;
    $('input#search').keyup(function(e) {
           searchGo();
           //clearTimeout(timer); 
           //timer = setTimeout(searchGo(), 800)
    });

    //searchGo();
});

function searchGo() {
    customersSearch();
    contactsSearch();
    invoicesSearch();
    ticketsSearch();
}

the code above processes the functions on input keyup

i have multiple functions that look like the below, the other functions have the same code but a different URL

function customersSearch() {
    var search_string = $("input#search").val();
    var trHTML = '';
    var resultLength = 0;

    $.ajax({
        type: "POST",
        dataType: "json",
        url: "/section/search_go?type=customers",
        data: { query: search_string },
        cache: false,
        success: function(response) {
            resultLength = response.length;

            if(search_string === '') {
                resultLength = 0;

                trHTML += '<tr>';
                trHTML += '<td colspan="4">No Results</td>';
                trHTML += '</tr>';
            } else {
                $.each(response, function(i, item) {
                    trHTML += '<tr ' + item.action + '>';
                    trHTML += '<td>' + item.accountnumber + '</td>';
                    trHTML += '<td>' + item.company + '</td>';
                    trHTML += '<td>' + item.phone + '</td>';
                    trHTML += '<td>' + item.postcode + '</td>';
                    trHTML += '</tr>';
                });
            }
            $('#customers').html(trHTML);
            $("#customers_counter").html("(" + resultLength + ")");
        }
    });
}

its searching and posting using ajax fine but if i clear the text input and try searching again it seems to take a while for it to finish and search again

charlie
  • 415
  • 4
  • 35
  • 83
  • Probably not a full solution, but you should try to use `.on('input', function(){ ... })` whenever possible. It's much closer to what people try to achieve by using `keyup` without a lot of the headaches. **Edit:** ooh! according to [this answer](http://stackoverflow.com/a/17384341/854246) keyup can be made cross-browser by adding the `propertychange` event in tandem. – Joseph Marikle Mar 07 '16 at 20:15
  • You should look into making one abstract function that takes the search term and url as parameters instead of all that duplicated code – Wesley Smith Mar 07 '16 at 20:15
  • It seems that you fired to much ajax calls at once / over the time with this solution. Have a look at network monitor of you preferred browser / browser debug extension. – Tino Rüb Mar 07 '16 at 20:28
  • There's no delay when I try it on JSFiddle. How exactly are you clearing the input? – vcanales Mar 07 '16 at 20:48
  • @DelightedD0D do you have any ideas? im sorry, im not great with JQuery – charlie Mar 07 '16 at 21:07
  • Sure, gimme a bit though I'm headed to work ;) – Wesley Smith Mar 07 '16 at 21:20
  • add this code $('input#search').off('keyup') after var timer=null; and try – Monah Mar 07 '16 at 21:27
  • unfortunately thats not working :( – charlie Mar 07 '16 at 21:59
  • hey @DelightedD0D - what do you reckon? – charlie Mar 08 '16 at 00:02
  • @HadiHassan How would that be helpful here? – Wesley Smith Mar 08 '16 at 01:43

2 Answers2

1

Here is how I would do this.

  • Have an object that stores callback functions, these functions will be used later to render the html from the response
  • Have a select box that lets the user choose what type of search they want to do or if they want to do all searches at once
  • Have a timer set up on the search input to detect when the user is done typing
  • When the user is done typing, pass the typed value, the type of search selected, and the appropriate callback to a doSearch() function that actually does the search
  • If "all" was selected, loop through all of the possible searches calling each with the appropriate parameters

The streamlined workflow, and proper use of a keyup timer, should solve the latency issues you are running into now and this abstraction will simplify and shorten your code as well as make it easier to change later. Say you want to add an "agents" search type, just add the "agents" option to the select box and a matching callback function and you're ready to go :)

Here is a jsFiddle

$(document).ready(function() {
  // create a json object to hold the callback functions we'll use to render the respone for each search type
  var callbacks = {
    customers: function(response) {
      resultLength = response.length;
      if (resultLength == 0) {
        trHTML = '<tr><td colspan="4">No Results</td></tr>';
      } else {
        $.each(response, function(i, item) {
          if (i > 0) {
            trHTML += '<tr><td>' + item.action + '</td><td>' + item.accountnumber + '</td><td>' + item.company + '</td><td>' + item.phone + '</td><td>' + item.postcode + '</td></tr>';
          }
        });
      }
      $('#customers').html(trHTML);
      $("#customers_counter").html("(" + resultLength + ")");
    },
    contacts: function(response) {
      // render code for contacts ...
    },
    invoices: function(response) {
      // render code for invoices ...
    },
    tickets: function(response) {
      // render code for tickets ...
    }
  }


  var timeout = null;
  $('#search').on('keyup', function() {
    var $this = $(this);
    if (timeout !== null) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(function() {
      var searchTerm = $this.val().toString().trim(); 
      if (searchTerm == '') return; // no input, abandon search
      $.each(callbacks, function(type, callback) {
        doSearch(searchTerm, type, callback);
      });
    }, 1000);
  });
  
});

function doSearch(searchTerm, type, callback) {
  $.ajax({
    type: "POST",
    dataType: "json",
    url: "/section/search_go?type=" + encodeURIComponent(type), // if the whole URL changes, you'll need pass in the URL and not just the type 
    data: {
      query: searchTerm
    },
    cache: false,
    success: function(response) {
      callback(response); // call our callback function and pass it the response
    }
  });

}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="search">
Wesley Smith
  • 19,401
  • 22
  • 85
  • 133
  • ah i see, okay i will give that a go. if i want to take out the `type` could i add in `var $options = ["customers", "contacts", "invoices", "tickets"];` and then it could loop these? would that work? – charlie Mar 08 '16 at 08:53
  • @charlie Yes, exactly. But note that you should also change the loop from `$options.each(function() {` to `$.each(options, function(i, option)`. The first syntax is meant for jQuery collections while the second is for arrays. Also note that I dropped the `$` in front of the `options` variable. I start my variables with a `$` when the variable is a jQuery object so I know what they are easily, its a somewhat common practice. If I were to change it to an array, I would remove the `$` – Wesley Smith Mar 08 '16 at 09:04
  • ok, i think ive got it. can you update the answer just so i can be sure please – charlie Mar 08 '16 at 09:05
  • @charlie actually, if you always want to do every search, you can just iterate over the callback object itself, updated the answer and the jsFiddle – Wesley Smith Mar 08 '16 at 09:16
  • @charlie and now that I think about it, we can abstract this out a good deal more so it only uses one callback function, but that'll have to wait till tomorrow I'm off to bed ;) – Wesley Smith Mar 08 '16 at 09:23
0

I have got a couple of suggestions that might improve your script.

  1. try to add a limited characters when somebody types something in the input. You could add a limit at least 3 characters before your requests run

  2. each time that a new character has been insert, keep a flag/variable and inside the callback success function, check if another request is in progress and don't apply the html code. Remember to reset this variable to false after the success function code has been executed

Nick
  • 156
  • 1
  • 11
  • These are comments not an answer – Wesley Smith Mar 07 '16 at 21:19
  • @DelightedD0D, First of all, based on the nature of the question, you cannot replicate the issue or to be sure 100% what the problem is. But the most important thing here is for the questioner to know what is doing and asking for advices and different, more efficient approach to his problem. I know sometimes you can give a piece of code that works but still it's not the point here. The point is to give advice and better solutions/approaches of what the other people want to do according your better experience that you might have in this particular issue. – Nick Mar 08 '16 at 23:40
  • I agree, except your *answer* offers only a vague *maybe try this, it might help*. If you laid out your suggestions and demonstrated how they could be implemented, this would pass for an answer. As currently posted, these are comments posted as an answer. IMHO, you dont give enough detail for this to effectively answer the question – Wesley Smith Mar 08 '16 at 23:46
  • @DelightedD0D, I agree, I could provide some sample code for how the limited characters and checking flag could be inside the success function. I might update my post soon. – Nick Mar 08 '16 at 23:52
  • But putting that aside, this wouldnt work anyway. You state: *"each time that a new character has been insert, keep a flag/variable and inside the callback success function, check if another request is in progress and don't apply the html code."* but remember, the OP is doing 4 simultaneous asynchronous searches. Good advice in general but that approach would not work here, you'd need something more robust – Wesley Smith Mar 08 '16 at 23:52
  • I think you can check in success callback for each request – Nick Mar 08 '16 at 23:57