Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to kill a Javascript function if it is called again?

I have a search box on my web page that has check boxes in order for the user to filter their results. Only one check box can be checked at once.

When a check box is clicked my code runs off and applies the filter to the list and returns the correct results.

The problem I have is that when a check box is clicked multiple times in quick succession, it queues the requests and pulls them back one by one. This can take a while if a check box is checked and then un-checked multiple times.

Is there any way in Javascript to inform the function that it has been called again and it should stop everything other than this last request?

like image 534
Win Avatar asked Aug 04 '14 13:08

Win


People also ask

How do you stop a function call?

When you click Call the function button, it will execute the function. To stop the function, click Stop the function execution button.

Does return terminate a function JavaScript?

The return statement stops the execution of a function and returns a value.

What is destroy function in JavaScript?

The destroy() function performs any processing necessary before the database server removes a row that contains opaque data. The database server calls the destroy() function just before it removes the internal representation of an opaque type from disk.


2 Answers

You want to wrap your onclick callback in a debouncing function like

http://underscorejs.org/#debounce

Say you have this

function search() {
    // ...
}

$jquery(".myFilterCheckboxes").click(search);

You should be able to just change the above to:

// Only allow one click event / search every 500ms:
$jquery(".myFilterCheckboxes").click(_.debounce(search, 500));

There are tons of debouncing functions out there, and writing your own isn't a big deal really if you can't or don't want to include underscore.js.

My first thought was towards debouncing because you mentioned multiple clicks creating multiple events in a short period. Debouncing is used really often for things like type-ahead search or autocomplete to provide a little space between key presses for thinking time.

As others have mentioned it may make more sense to simply disable the checkboxes / click event while your search is running. In that case, try something like this:

function disableClick(elem) {
  elem.unbind("click");
  elem.attr("disabled", true);
}

function enableClick(elem, onclick) {
  // Enable click events again
  elem.live("click", search);
  // Enable the checkboxes
  elem.removeAttr("disabled");
}

function search() {
  var boxes = $jquery(".myFilterCheckboxes");
  disableClick(boxes);
  $.get(...).always(function() {
    enableClick(boxes, search);
  });
}

$jquery(".myFilterCheckboxes").live("click", search);

Why disable the click event, add the disabled attribute to the checkboxes instead of just a global lock variable? Well, global locks can be somewhat error prone, but more than that, we already have a global object that matters in the DOM. If we just modify the DOM state we get the right behavior and signal to our users that they should chill out on the checkboxes until the search completes.

That said, it probably makes sense with any kind of locking / unbinding scenario to indicate to the user with a loading spinner or something that you're doing work.

like image 177
stderr Avatar answered Oct 08 '22 15:10

stderr


You can use a lock pattern:

http://jsfiddle.net/RU6gL/

HTML

<input type="checkbox" onclick="fire()" >CB1
<br />
<input type="checkbox" onclick="fire()" >CB2

JS

function_lock = false

fire = function() {
    // First, check the lock isn't already reserved. If it is, leave immediately.
    if (function_lock) return;

    // We got past the lock check, so immediately lock the function to 
    // stop others entering
    function_lock = true;

    console.log("This message will appear once, until the lock is released")

    // Do your work. I use a simple Timeout. It could be an Ajax call.
    window.setTimeout(function() {
        // When the work finishes (eg Ajax onSuccess), release the lock.
        function_lock = false;
    }, 2000);
}

In this example, the function will only run once, no matter how many times the checkboxes are clicked, until the lock is released after 2 seconds by the timeout.

This pattern is quite nice, because it gives you control opver when you release the lock, rather than relying on a timed interval like 'debounce'. For example, it will work with Ajax. If your checkbox is triggering an Ajax call to do the filtering, you can:

  1. On first click, set the lock
  2. Call the Ajax endpoint. Subsequent clicks won't call the Ajax endpoint.
  3. In the Ajax success function, reset the lock.
  4. The checkboxes can now be clicked again.

HTML

<input type="checkbox" onclick="doAjax()" >CB2

JS

ajax_lock = false

doAjax: function() {
    // Check the lock.
    if (ajax_lock) return;

    // Acquire the lock.
    ajax_lock = true;

    // Do the work.
    $.get("url to ajax endpoint", function() {
         // This is the success function: release the lock
         ajax_lock = false;
    });   
} 
like image 43
sifriday Avatar answered Oct 08 '22 17:10

sifriday