DavidDunham
DavidDunham

Reputation: 1362

Calling a function only once after fast calls

I have a search button the user can click.

This search button calls a function. I want to avoid that the function is executed multiple times when the user clicks the search button twice or more (because he thinks that nothing has happened).

I am thinking of using setTimeout(function(){}) somehow and in the end only call the search function again if the click on the button is at least 3 seconds away from the last click.

Example: https://jsfiddle.net/n1rcre75/ - I want to be able to click the button twice in a row (after 1 second) but have the execute function only run once

Any ideas?

Upvotes: 1

Views: 3600

Answers (9)

Francisco Goldenstein
Francisco Goldenstein

Reputation: 13767

I created a constructor to handle this in a reusable way. You can provide a delay when you create the object or when you invoke it. It has a default of 300ms.

function FunctionInvoker(waitTime) {
    this.timerIdentifier = null;
    this.waitTime = waitTime || 300;

    var self = this;

    this.invoke = function (callback, waitTime) {

        self.cancel();

        self.timerIdentifier = setTimeout(function () {
            self.cancel();
            callback();
        }, waitTime || self.waitTime);
    };

    this.cancel = function () {
        if (self.timerIdentifier != null) {
            clearTimeout(self.timerIdentifier);
            self.timerIdentifier = null;
        }
    }
}

To use it:

var functionInvoker = new FunctionInvoker();

functionInvoker.invoke(function () {
     // whatever you want to do (callback function)
     saveMyData(); // for ex: save data
});

I used this code when dealing with a slider. The slider was making an AJAX call too many times. By using the functionInvoker I was able to only make the AJAX call when slider keeps the same value for Xms.

Upvotes: 1

DavidDunham
DavidDunham

Reputation: 1362

This function can be used to make it work without any additional states or parameters that have to be cared for

function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};

https://jsfiddle.net/cpg584pp/

Upvotes: 0

IYH
IYH

Reputation: 80

took your fiddle and made a few changes, the

setTimeout(function(){
//stuff
},3000);

is only to simulate the actual searching

https://jsfiddle.net/n4fhaqad/

Upvotes: 1

nocksock
nocksock

Reputation: 5527

Just guard the search:

var button = document.getElementById('search');
var runSearch = true;

button.addEventListener('click', function(evt) {
        evt.preventDefault();

        if(!runSearch){
                return;
        }

        console.log('do search');

        runSearch = false;          
        setTimeout(function(){
                runSearch = true;
        }, 3000);
});

Or, if you don't want to introduce another variable to the scope:

document.getElementById('search').addEventListener('click', (function() {
        var runSearch = true;

        return function(evt)  {
                evt.preventDefault();

                if(!runSearch){
                        return;
                }

                runSearch = false;
                console.log('do search');

                setTimeout(function(){
                        runSearch = true;
                }, 3000);
        }
})());

Upvotes: 3

Abhi
Abhi

Reputation: 4261

A generic code. You can add avoid_double_click class to that link/button on which you want to avoid multiple clicks

jQuery('.avoid_double_click').on('click', function(e) {
    var onclick_event = jQuery(this).attr('onclick');
    jQuery(this).removeAttr("onclick");
    var that = this;
    setTimeout(function(){
      jQuery(that).attr('onclick', onclick_event);
    },2000);
  });

Upvotes: 0

Try this code:

<html>
    <head>
        <script type="text/javascript" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
        <script>
            $(document).ready(function() {
                $('button').click(function() {
                    $('button').prop('disabled', true);
                    setTimeout(function() {
                        $('button').prop('disabled', false);
                    }, 3000);
                });

            });
        </script>
    </head>
    <body>
        <button>Click me</button>
    </body>
</html>

Upvotes: 0

Zee
Zee

Reputation: 8488

Just another solution:

<button onclick="buttonClick()">Click</button>

<script>
  var running = false;
  function buttonClick(){
        if(running == false){
          running = true;
          //your code
          setTimeout(function(){running = false}, 3000);
        }
  }
</script>

Upvotes: 0

TeraTon
TeraTon

Reputation: 435

When you call you our function from the press event, disable the original button for the time the function runs, for example using the get element by Id:

function(foo){
document.getElementById("yourButtonId").disabled = true;

//do your function

document.getElementById("btnPlaceOrder").disabled = false;  
}

of course this use case is not perfect for all situations, where for example you want to do additional calls inside the function or even xhr. If you have callbacks you should re-enable the button in those.

Upvotes: 0

Nikola Nikolov
Nikola Nikolov

Reputation: 1310

Make the button inactive until your search function return success or error, or until the user change the search string.

Upvotes: 0

Related Questions