2

I have some JavaScript to execute logic i.e. doSomething() when a button is clicked. I know the class of the buttons, but there are multiple buttons on the page with this same class. The problem with my code below is that the doSomething() function is executed once for every button on the page when I only want it to execute one time only.

var myButtonClass = $(".my-button-class");
if (myButtonClass) {
    myButtonClass.click(function (event) {
        if (someCondition) {
            doSomething();
        }
    });
}

I know it would be better to select by button div, but the button div names all vary based on how many there are (i.e. #my-button-div1, #my-button-div2, etc.) and the number of buttons is indefinite.

Is there a way to only do this event once? I don't care which button in the class happens to be clicked, I just need the event to fire once and then it's done.

UPDATE: To be clear, I still want the logic to execute if the user clicks another button on the page again, so I don't want to completely unbind the event. I just don't want it to execute once for every button on the page. For example, let's say I have 4 buttons. Right now it's doing something like the following when just one button is clicked:

alert!
alert!
alert!
alert!

I only need ONE of those alerts. Basically, whenever the user clicks any of the buttons on the page, I need it to go alert! only once per click.

2
  • if (myButtonClass) { will always be true even when there are no elements... Commented Mar 16, 2016 at 3:42
  • So unbind the event after the click... Commented Mar 16, 2016 at 3:43

3 Answers 3

2

Revised so that you don't have weird if statements, and allows for other click handlers to happily work if binded elsewhere

UPDATED:

var clickHandler = function handleClick(event) {
  doSomething();
}
var bindClicks = true;

function doSomething() {
  alert('alert!');  
}

function doTheBinding() {
  if (bindClicks) {
      $('.my-button-class').on('click', clickHandler);
      bindClicks = false;
  }
}

// as many times as you want but it will still call once
doTheBinding();
doTheBinding();
doTheBinding();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button class="my-button-class">Click me!</button>
<button class="my-button-class">Click me!</button>
<button class="my-button-class">Click me!</button>
<button class="my-button-class">Click me!</button>

Sign up to request clarification or add additional context in comments.

5 Comments

I updated my question to be more clear. The problem here is that I still need the event to fire (just once) if any of the buttons are clicked again.
How about the revised one now?
it still feels like @FionaCat86 is binding the 'on' callback more than once. Which would call alert more than once.
This isn't as good as my answer because in mine, there are closures which present accidental/deliberate alteration of the bindClicks variable by other code.
I agree with you @4castle, global scoping isn't as great. It was to figure out what the real issue was. On the counter side, you may want to rebind later by unbinding everything and toggling the bindClicks again.
1

You can use on() and off() to bind and unbind the event on an element respectively.

$('.my-button-class').on('click', function (event) {
    if (someCondition) {
        doSomething();

        // Unbind the event on all the elements having the class
        $('.my-button-class').off('click');

        // To unbind the event on only the clicked element
        // $(this).off('click');
    }
});

Sidenote: if (myButtonClass) { will always evaluate to true. jQuery returns an object even when the element is not found and an object is always truthy. To check if an element exists in DOM, use length property on the jQuery object $('someSelector').length > 0.

4 Comments

Maybe $('.my-button-class').off('click', this); so it keeps other click bindings
@juz Yes, that can also be used, but for me $(this).something looks much clear, readable.
That's not what I meant, it's to do with handle callbacks
I have a solution that is much cleaner and bug free. See my answer.
1

If you give the handler a local boolean variable that is protected with a closure, you can create a function that will execute only once. See this SO answer.

Run the code snippet below to see it in action.

$(".my-button-class").click(function() {
  var executed = false;
  return function() {
    if (!executed) {
      executed = true;
      doSomething();
    }
  };
}());

function doSomething() { 
  alert("You should only see me once!");
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="my-button-class">Click me!</button>
<button class="my-button-class">No click me!</button>

UPDATE: To address a different issue of the click event getting bound more than once. Just do a similar thing with:

var bind = function() {
    var bound = false;
    return function() {
        if (!bound) {
            bound = true;
            $(".my-button-class").click(function() {
                if (someCondition)
                    doSomething();
            });
        }
    };
}();
bind();
bind(); // won't execute second time

var someCondition = true;
function doSomething() {
  $("#output").append("<br>alert!");
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="my-button-class">Click me!</button>
<button class="my-button-class">No click me!</button>
<span id="output"></span>

4 Comments

The problem here is that I still want it to execute once when the user goes to click the same (or another) button again. I just don't want it to execute once for every button on the page.
oh it should only execute once if done his way, if it's still executing multiple times.. you're binding the on.('click') binding multiple times
@FionaCat86 That's confusing. Your question seemed pretty clear. Can you create a code snippet that has that problem? I don't see how it would execute once for every button in the first place.
@FionaCat86 I added another code snippet to answer that question also. Would you like me to just remove the first part of my answer so you can select it as the answer?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.