tags:

views:

73

answers:

5

I am trying to prevent multiple clicks on links and items, which is causing problems.

I am using jQuery to bind click events to buttons (jQuery UI) and image links (<a><img /></a>).

Is there a way to do-once-for-all prevent other events from firing after a click occurs?

Or do I have to maintain a global variable called _isProcessing and set it to true for each event handler?

Thanks

Edit: (clarification) Thanks for your answers, my problem isn't preventing the bubbling of the event, but preventing multiple concurrent clicks.

+3  A: 

did you check out preventDefault?

$("a").click(function(e) {
    e.preventDefault();
}

you could also try stopImmediatePropagation() or stopPropatation()


You could also look into the one() event.

Attach a handler to an event for the elements. The handler is executed at most once per element.

hunter
The `e.preventDefault()` method really doesn't stop handlers. It prevents the default behavior of an element from activating (like an `<a>` taking you to its `href` location).
patrick dw
+3  A: 

Return false from your event handlers, or call ev.stopPropagation() in every handler.

Gintautas Miliauskas
Use .stopPropagation()
Mark
@Mark - Re-read the question. *"my problem isn't preventing the bubbling of the event,"*
patrick dw
I clarified the question after he posted his answer.
Russell
@Russell - My comment was referring to @Mark's comment, not @Gintautas' answer. You're right, the answer was posted before your clarification.
patrick dw
+4  A: 

There is event.preventDefault, event.stopPropagation and return false as already stated.

$("a").click(function(e) {
    e.preventDefault();
    e.stopPropagation();
    return false;
}
TehOne
:-) for good measure... (though the question is different, I guess...)
andras
yep, when I answered the question hadn't been clarified yet.
TehOne
Yeah sorry @TehOne, I didn't express my question properly first time round.
Russell
+4  A: 

There are various ways to prevent concurrent clicks from running the code.

One way is to unbind('click') on the element, then .bind() it again when you're ready.

I'd rather use some sort of flag. It could be a variable, but I'd rather assign a class to the element, like .processing, and remove it when done. So you would have the handler check for the existence of that class to determine of the code should run.

$('someElement').click(function() {
    var $th = $(this);
    if($th.hasClass('processing'))
          return;
    $th.addClass('processing');
    // normal code to run
    // then when done remove the class
    $th.removeClass('processing');
});

Another option is to use the elements .data() to set a similar flag, like $(this).data('processing', true); Then set it to false when done.

patrick dw
Nice solution. Very clean and straight to the point.
TehOne
Ah, beat me to it, you did. Like the class idea; could even be used to provide some visual feedback to the user. +1!
elo80ka
@elo80ka - Thanks. I wish jQuery had something like `.disableHandler('click')` and `.enableHandler('click')` as an alternative to `.bind()/unbind()` and somewhat cluttered/hackish solutions like using classes or variables as flags. :o)
patrick dw
You should use the .data() function rather than adding a class that might accidentally impact the display of the element.
bcherry
@bcherry - The nice thing about using a class is that it is (I'm pretty sure) a lighter weight operation than using `.data()`. If you're careful with naming your class, there shouldn't be any display ramifications.
patrick dw
Actually it might not be. You'd be modifying the DOM, and then it would have to look through the CSS again to see if it needs to update styling, etc. jQuery's `.data` method stores it in an in-memory hash that jQuery owns, and gets/sets to it will probably be faster.Note that I have done no such benchmarking, this is all speculation.
bcherry
@bcherry - Interesting thought. I'd be curious to know the performance difference. The browser looking for the class in CSS would be an in-memory lookup as well, and using native code, so it should be much faster than lookups in javascript, but touching the DOM is another issue. I've heard that calling `.data()` is very slow, such that it has been recommended to cache a reference to an element's data when recurring calls are required (as in this situation). Maybe I'll do some tests tomorrow.
patrick dw
+1  A: 

You've got a couple of options:

  1. If your buttons/links will reload the page, you can simply unbind the click event handler:

    $('input:submit').click(fumction() {
        $(this).unbind('click');
        // Handle event here 
    })
    
  2. You can disable the buttons, and re-enable them once you're done (I think this should also work with <input type="image">):

    $('input:submit').click(function() {
        $(this).attr('disabled', 'disabled');
        // It also helps to let the user know what's going on:
        $(this).val('Processing...');
        // Handle event here 
        $(this).removeAttr('disabled');
    })
    

    I don't think this works on links though.

elo80ka
Do you know if there is a way to disable events (not unbind, just disable)?
Russell
@Russell: You can disable input elements. As far as I know, disabled elements don't raise events.
elo80ka
Yeah but an image link (anchor), for example, could raise a click event but is not an input field (as you said, disabling anchor elements doesn't work).
Russell
True...can't think of any way 'round that. Except, maybe, replacing your image links with `<input type="image">` elements. I'd probably go with Patrick's custom class solution.
elo80ka