Stop jQuery from calling next events - javascript

I write a jQuery plugin the first time and I'm wondering if there is a way to stop jQuery from running the next attached events.
Example:
$(this).submit(function(){
return $(this).do_some_validation();
}
If validation didn't pass (i.e. the function returned false), the form should not be submitted, but if there are any other event handlers attached, only last handler return value can prevent form from being submitted.

You may also want to look at event.stopImmediatePropagation, as stopPropagation "will not prevent other handlers on the same element from running" (for example, two submits handlers on the same form should still be triggered if using stopPropagation).

Use the stopPropagation() method:
$(this).submit(function(e){
e.stopPropagation();
return $(this).do_some_validation();
}

You may take a look at the event.stopPropagation() function.

stopPropagation() works on most events but may not always work on delegated events, .live() and .delegate().
return false; is a fool proof way if stopPropogation doesn't work first.

I use this functions with .live() and never have problems
jQuery("a.entryTable, a.entryDelete").live("click", function(e) {
e.preventDefault();
e.stopPropagation();
// code
return false;
});

Related

What causes preventDefault to let the original event through

I don't have an example at hand, but in some situations calling event.preventDefault() lets the original event through (navigating to page, submitting form etc) but returning false helps. What could cause this?
You don't have an example to hand? OK, let me invent one that may or may not be whatever it was you were thinking of.
Remember that return false; is the equivalent of calling both event.preventDefault(); and event.stopPropagation(). EDIT: This applies with jQuery, which explictly implements this behaviour and also normalises event.preventDefault() and event.stopPropagation() for use in all browsers. It doesn't work that way in all browsers with "plain" JS, in fact older IE versions don't support event.preventDefault() at all, they have their own equivalent event.returnValue = false;
If you have nested elements and you handle the same event in several levels then calling event.preventDefault() will not stop the outer elements' event handlers from running, but return false will because it stops propagation of the event.
An example that demonstrates it: http://jsfiddle.net/nnnnnn/KjLv3/
<span>Click me to see an alert</span>
// using jQuery for simplicity in the example:
$("a span").click(function(e){
e.preventDefault();
});
$("a").click(function() {
alert("Hello");
});
The alert will display. If you change the "a span" handler to return false the alert will not display.
event.preventDefault() prevents the browser from performing the default action ( if the event is cancelable ) without stopping further propagation of the event, whereas
return false prevents the event from propagating (or "bubbling up") the DOM, along with preventing the default action.
So,
function() {
return false;
}
// IS EQUAL TO
function(e) {
e.preventDefault();
e.stopPropagation();
}

preventDefault() doesn't prevent the action

When I use event.preventDefault() on a link it works, however when I use it on a button doesn't!
DEMO
My code:
<a id="link" href="http://www.google.com">link</a>
<button id="button" onclick="alert('an alert')">button</button>​
$('#link').click(function(event){
event.preventDefault();
});
$('#button').click(function(event){
event.preventDefault();
});
​
Link action is cancelled, but when I click on the button, still executes the onClick action.
Any help? what I want to do is to prevent the button onClick action without changing the button html (I know how to do
$('#button').removeAttr('onclick');
You want event.stopImmediatePropagation(); if there are multiple event handlers on an element and you want to prevent the others to execute. preventDefault() just blocks the default action (such as submitting a form or navigating to another URL) while stopImmediatePropagation() prevents the event from bubbling up the DOM tree and prevents any other event handlers on the same element from being executed.
Here are some useful links explaining the various methods:
http://api.jquery.com/event.preventDefault/
http://api.jquery.com/event.stopPropagation/
http://api.jquery.com/event.stopImmediatePropagation/
However, since it still doesn't work it means that the onclick="" handler executes before the attached event handler. There's nothing you can do since when your code runs the onclick code has already been executed.
The easiest solution is completely removing that handler:
$('#button').removeAttr('onclick');
Even adding an event listener via plain javascript (addEventListener()) with useCapture=true doesn't help - apparently inline events trigger even before the event starts descending the DOM tree.
If you just do not want to remove the handler because you need it, simply convert it to a properly attached event:
var onclickFunc = new Function($('#button').attr('onclick'));
$('#button').click(function(event){
if(confirm('prevent onclick event?')) {
event.stopImmediatePropagation();
}
}).click(onclickFunc).removeAttr('onclick');
you need stopImmediatePropagation not preventDefault. preventDefault prevents default browser behavior, not method bubbling.
http://api.jquery.com/event.stopImmediatePropagation/
http://api.jquery.com/event.preventDefault/
The preventDefault function does not stop event handlers from being triggered, but rather stops the default action taking place. For links, it stops the navigation, for buttons, it stops the form from being submitted, etc.
What you are looking for is stopImmediatePropagation.
you can try this:
$('#button').show(function() {
var clickEvent = new Function($(this).attr('click')); // store it for future use
this.onclick = undefined;
});
DEMO
It have helped me
function goToAccessoriesPage(targert) {
targert.onclick.arguments[0].preventDefault();
...
}

jQuery click events overriding each other

I have the following jQuery:
$('.io-sidebar-section').click(function () {
console.log('Section Clicked');
$(this).next().fadeToggle('fast',function(){});
});
$('.io-sidebar-section-advanced-toggle').click(function(){
$(this).parent().next().children('.io-sidebar-link-advanced').fadeToggle('fast',function(){});
});
the advanced toggle is inside of a sidebar section. When I click on the advanced toggle, it executes the sidebar section click.
How can I seperate these two out?
You can use the stopPropagation method of the event object inside the click event handler for the child element:
$('.io-sidebar-section-advanced-toggle').click(function(e){
e.stopPropagation();
$(this).parent().next().children('.io-sidebar-link-advanced').fadeToggle('fast',function(){});
});
From the jQuery docs, here's what stopPropagation does:
Prevents the event from bubbling up the DOM tree, preventing any
parent handlers from being notified of the event.
As mentioned in the comments, if you prefer you can alternatively use return false in the event handler (in this particular case, as far as I can tell anyway - it will also cause preventDefault which may not be what you want to happen). My personal preference is to use stopPropagation but it's completely up to you.
You can avoid events bubbling up by using jQuery's bind function and preventBubble argument.
http://api.jquery.com/bind/

Two submit event handlers on a form. One must stop the other

I have to event handlers attached to a form. The first one that fires should stop the other event if a condition is not met.
The code below does not work, as both events will be triggered. Can you help me?
Thanks!
//fires first
$("#myform").submit(function(){
if (some validation) {
alert("You need to make the form valid");
return false;
}
});
//fires second
$("#myform").submit(function(){
//ajax stuff
return false;
});
p.s. I have to this as the ajax stuff is in a plugin that is not changeable. I cannot avoid two event handlers
Have a look at event.stopImmediatePropagation():
Keeps the rest of the handlers from being executed and prevents the event from bubbling up the DOM tree.
$("#myform").submit(function(event){
if (some validation) {
event.stopImmediatePropagation();
alert("You need to make the form valid");
return false;
}
});
You might also want to use event.preventDefault().
Update: Just to clarify: You can rely on the order the event handlers are called. From jQuery's bind method:
When an event reaches an element, all handlers bound to that event type for the element are fired. If there are multiple handlers registered, they will always execute in the order in which they were bound. After all handlers have executed, the event continues along the normal event propagation path.
The order might not be defined in W3C's original definition but it works with jQuery. Otherwise, the above named function would be unnecessary anyway ;)
In short, no. If you have two event handlers, then you have two event handlers. That said however, there are ways around it.
First, remember that javascript execution is single-threaded. If you define a global variable, say var haveCalledSubmit=0;, then you can use that to synch your handlers. For example, if you start each handler function with this:
if(haveCalledSubmit == 1)return haveCalledSubmit = 0;
else haveCalledSubmit = 1;
Then only one of the two handlers will be called. You can easily modify it to match some condition, or to deal with more than two functions.
An alternative is to look into event propagation models. This page will give you all the information you need, although Felix has already mentioned an ajax command that may do what you want.

In JavaScript event handling, why "return false" or "event.preventDefault()" and "stopping the event flow" will make a difference?

It is said that when we handle a "click event", returning false or calling event.preventDefault() makes a difference, in which
the difference is that preventDefault
will only prevent the default event
action to occur, i.e. a page redirect
on a link click, a form submission,
etc. and return false will also stop
the event flow.
Does that mean, if the click event is registered several times for several actions, using
$('#clickme').click(function() { … })
returning false will stop the other handlers from running?
I am on a Mac now and so can only use Firefox and Chrome but not IE, which has a different event model, and tested it on Firefox and Chrome by adding 3 handlers, and all 3 handlers ran without any stopping…. so what is the real difference, or, is there a situation where "stopping the event flow" is not desirable?
This is related to
Using jQuery's animate(), if the clicked on element is "<a href="#" ...> </a>", the function should still return false?
and
What's the difference between e.preventDefault(); and return false?
hopes this code can explain it to you...
html
<div>
click me
click me
</div>​
jquery
$('div').click(function(){
alert('I am from <div>');
});
$('a.a1').click(function(){
alert('I am from <a>');
return false; // this will produce one alert
});
$('a.a2').click(function(e){
alert('I am from <a>');
e.preventDefault(); // this will produce two alerts
});​
demo
or
$('div').click(function(){
alert('I am from <div>');
});
$('a').click(function(){
alert('I am from <a>');
});
$('a.a1').click(function(){
alert('I am from <a class="a1">');
return false;
});
$('a.a2').click(function(e){
alert('I am from <a class="a2">');
e.preventDefault();
});​
demo 2
Writing return false or e.preventDefault() will not prevent other handlers from running.
Rather, they will prevent the browser's default reaction, such as navigating to a link.
In jQuery, you can write e.stopImmediatePropagation() to prevent other handlers from running.
return false and preventDefault() are there to prevent the browser's default action associated with an event (for example, following a link when it's clicked). There is a different technique to achieve this for each of three different scenarios:
1. An event handler added using addEventListener() (non-IE browsers). In this case, use the preventDefault() method of the Event object. Other handlers for the event will still be called.
function handleEvent(evt) {
evt.preventDefault();
}
2. An event handler added using attachEvent() (IE). In this case, set the returnValue property of window.event to true. Other handlers for the event will still be called, and may also change this property.
function handleEvent() {
window.event.returnValue = false;
}
3. An event handler added using an attribute or event handler property.
<input type="button" value="Do stuff!" onclick="return handleEvent(event)">
or
button.onclick = handleEvent;
In this case, return false will do the job. Any other event handlers added via addEventListener() or attachEvent() will still be called.
function handleEvent() {
return false;
}
Sometimes an event listener wants to cancel the sideeffects of the event is is interested in. Imagine a textbox which you wish to only allow numbers. Because textboxes can accept anything it becomes necessary to tell the browser to ignore non numbers that are typed. This is achieved by listening the key events and returning false if the wrong key is typed.
This doesn't completely answer your question, but the other day I used YUI's e.preventDefault() on an <a> element to squash the href action, as I only wanted the JavaScript onclick event to have control (unless no JS detected). In this situation stopping the entire chain of events wouldn't effect me.
But a couple days before that, I had an <input type="checkbox"> nested inside a <label> element, and I had to use a conditional in the event handler to determine if the clicked target was a label, as neither e.preventDefault() nor e.stopEvent() stopped my 'click' event from (legitimately) triggering twice (except in IE6).
What would have been nice is the ability to squash an entire chain of related events, since I'd already tried propagation and return false ;, but I was always going to get a 2nd event fire thanks to my label element.
Edit: I wouldn't mind knowing how jQuery would've handled my double-event situation, if anyone's keen to comment on that.

Categories