Jquery stop event from triggering - javascript

I have simple scenario as shown in fiddle which is
Initially event is binded on only one button A and click event is triggered in both the buttons(A & B) manually.
Now in event handler of button A the event handler for button B is binded. It is expected not to execute the callback of B as it is binded after the event is triggered.
But the callback is still executed. Where am i going wrong?
HTML:
<div>
<button class="a">botton A</button>
<button class="b">button B</button>
</div>
JS:
$(function () {
$('div').on('click', '.a', function (e) {
e.preventDefault();
$('div').on('click', '.b', function () {
alert('Can"t see me')
});
});
$('button').trigger('click');
});
FIDDLE LINK
EDIT:
I have this scenario in my project and
now I knew why is this happening :). But how can i stop event from propagating?

$('button').trigger('click'); triggers a click event on both buttons in the order they appear in the document markup. Since event bubbling is synchronous, the event for .b is binded before the click event is triggered on that button. Here's the breakdown:
$('button') creates a collection of button .a and button .b.
.trigger('click'); iterates through each button in the collection and generates a click event.
button .a receives the click event and runs its event handler you registered for it on page load.
The event handler for .b is registered within the callback of the event handler for .a.
button .b receives the click event from .trigger('click'); since it's second in the collection.
The callback of the event listener for button .b triggers the popup alert.
Since you only want to trigger button .a to be clicked, any of the following will work on your current document:
$('.a').trigger('click');
$('button.a').trigger('click'); (though this is redundant)
$('button').get(0).trigger('click'); (since .a is the 0th indexed button element)
EDIT Although this is unrelated to the question, Perhaps you meant to register the event for .b only once, doing this:
$('.a').one('click', function (e) {
$(function() {
$('.a').one('click', function(e) {
e.preventDefault();
$('div').on('click', '.b', function() {
alert('Can\'t see me');
});
});
$('.a').trigger('click');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<button class="a">button A</button>
<button class="b">button B</button>
</div>
SECOND EDIT If you want to stop event propagation, you need to add another event listener, like this:
$(function() {
$('.a').one('click', function() {
$('.b').on('click', function(e) {
e.stopPropagation();
alert('Can see me');
});
$('div').on('click', '.b', function() {
alert('Can\'t see me');
});
});
$('button').trigger('click');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<button class="a">button A</button>
<button class="b">button B</button>
</div>

It's because of $('button').trigger('click');.
This triggers a click on every button - first it clicks on .a, which binds the click handler to .b, then it clicks on .b.
In my experiment, simply putting button .b first fixed this, but I wouldn't rely on that.

This is probably because the click is being triggered on all button instances serially...
button a click gets executed first...in its callback you bind button b click callback...
...then...button b click gets executed...hence callback for b gets executed...
All of this happens in that one call: $('button').trigger('click');
Edit: others have probably answered this before I have...but to iterate trigger the click on the correct element :
$('.a').trigger('click');

The order of the execution is:
bind .a
trigger first button (say, a)
callback for a: bind b
trigger second button (b)
callback for b
Even $("button").trigger("click") is a single line, it is a kind of loop, works like if it were:
var buttonElms = $("button");
for (var index in buttonElms) {
buttonElms[index].trigger("click");
}

Related

stopPropagation() of a different event

How can I listen to a change event on a checkbox without triggering a click event on its container?
<label><input type="checkbox"> Hello world</label>
I want to trigger an action on the checkbox's change event, but I don't want it to bubble up to a click event on the label.
(function ($) {
$('input').change(function (v) {
v.stopPropagation();
});
$('label').click(function () {
alert('You should not see this message if you click the checkbox itself!');
});
})(jQuery);
http://jsfiddle.net/r49PA/
Any ideas? Thanks!
The issue is that two events are triggered when you click the checkbox -- a change and a click. You're only catching the change, so the click isn't ever being told to stop propagation. You need to either add a second handler on the checkbox for click events, or combine one handler to catch both types, like this:
$('input').on('change, click', function (v) {
v.stopPropagation();
});
Here's a jsFiddle demonstrating a combined handler: http://jsfiddle.net/r49PA/4/
You can stop propagation on click event instead of change event since you bind click event for the parent label:
$('input').click(function (v) {
v.stopPropagation();
});
Updated Fiddle
With plain javascript you can do something like this:
var stopPropagation = false;
selector.addEventListener('mousedown', function(event) {
// simulating hold event
setTimeout(function() {
stopPropagation = true;
// do whatever you want on the `hold` event
})
}
selector.addEventListener('click', function(event) {
if (stopPropagation) { event.stopPropagation(); return false; }
// regular event code continues here...
}
Since mousedown and click events are overlapping, we want the click event to not be triggered when we are trying to get the hold state. This little helper flag variable stopPropagation does the trick.

button click event triggering wrong event handler

I have a div display some titles of music which is clickable. When you click it it will show some more detail information. Then I also have a button in the clickable div. When I click the button. It won't call the function of the button but the function of the div? Is there a way to solve this? Thank you!
$("#myComList").append("<div id="+comListID+" class=listDiv> <p class=comTitle><? echo $row["compositionTitle"] ?>(<?echo $row["year"]?>)</p><button id="+comListID+"btn class=addNewArrBtn>Add new Arrangement</button> <p class=comOri>BY <? echo $row["OrigComposer"] ?></p> </div>");
$('#'+comListID).click(function() {
$(this).find("li").slideToggle('slow', function() {
});
$("#"+comListID+"btn").click(function(){
addNewArr(comListID);
});
It's called 'bubbling'. The button is inside the div so it's executing button then up the chain to div. Add event.stopPropagation() inside the button function.
$("#"+comListID+"btn").click(function(event){
event.stopPropagation();
addNewArr(comListID);
});
From jQuery documentation:
By default, most events bubble up from the original event target to
the document element. At each element along the way,
jQuery calls any matching event handlers that have been attached.
A handler can prevent the event from bubbling further up the document
tree (and thus prevent handlers on those elements from running) by
calling event.stopPropagation(). Any other handlers attached on the
current element will run however. To prevent that, call
event.stopImmediatePropagation(). (Event handlers bound to an element
are called in the same order that they were bound.)
http://api.jquery.com/on/
So you'd call event.stopPropagation() inside the button click handler, as to stop the div event from firing.
I believe I understand your question without seeing the code. The problem it sounds like stems from the click event bubbling or propagating up. Below is a sample of code to try and a link to a fiddle for you to test:
<div id="testDiv" onclick="alert('Stop Clicking Me!');">
<button type="button" onclick="function(e) { alert('You hit the button!'); e.stopPropagation(); }">Click Me!</button>
</div>
In this function, the:
e.stopPropagation();
prevents the click event from filtering up to its parent container (in this case "testDiv") and triggering its click event as well. You can test it and see for yourself in the jsfiddle below:
Test Fiddle
EDIT:
In your case:
$("#"+comListID+"btn").click(function(e){
addNewArr(comListID);
e.stopPropagation();
});
add the event parameter to the click function and stop it from propagating to the parent.
Hope this helps.

Each submit button calls the same function

I'm calling function for selecting component ID after page refresh:
$(document).ready(
function() {
document.getElementById('form:#{myBDE.componentId}').focus();
document.getElementById('form:#{myBDE.componentId}').select();
}
)
My submit button example:
<h:form id="form">
<h:commandButton id="btnSubmit" action="#{myBDE.save}" type="submit" >
<f:ajax execute="#form" render="#form"/>
</h:commandButton>
...
</form>
How can I create the same function to be called each time I click any submit button (I'm using ajax, so I'm working without page reloading, document.ready is not enough for me). Is it possible?
update (partially functional solution):
var myFunc = function() {
document.getElementById('form:#{myBDE.componentId}').focus();
document.getElementById('form:#{myBDE.componentId}').select();
};
$(document).ready(function() {
myFunc();
$('input[type=submit]').click(myFunc);
});
I can call the function adding onclick="return myFunc();" to h:commandButton, problem is, that <f:ajax> render the form after calling the function, so the select and focus is cleared :(
Give the function a name (currently, its an anonymous function), and then call the function as and when you need.
$(document).ready(
onPageLoad(); // call it when page loads
$('form').submit(onPageLoad); // also call whenever a form is submitted
)
function onPageLoad() {
document.getElementById('form:#{myBDE.componentId}').focus();
document.getElementById('form:#{myBDE.componentId}').select();
return true;
}
This should work
$('input[type="submit"]').click(function(){
document.getElementById('form:#{myBDE.componentId}').focus();
document.getElementById('form:#{myBDE.componentId}').select();
});
In fact you can bind a function to any events. In this case it is the click event for the input tag with the attribute type=submit
You should delegate the handler to a higher-level dom element:
$(document).ready(function() {
$('h:body').on('click', 'input[type=submit]', function() {
document.getElementById('form:#{myBDE.componentId}').focus();
document.getElementById('form:#{myBDE.componentId}').select();
});
});
See jQuery.on().
When a selector is provided, the event handler is referred to as
delegated. The handler is not called when the event occurs directly on
the bound element, but only for descendants (inner elements) that
match the selector. jQuery bubbles the event from the event target up
to the element where the handler is attached (i.e., innermost to
outermost element) and runs the handler for any elements along that
path matching the selector.
And then later:
Delegated events have the advantage that they can process events from
descendant elements that are added to the document at a later time. By
picking an element that is guaranteed to be present at the time the
delegated event handler is attached, you can use delegated events to
avoid the need to frequently attach and remove event handlers.
So the event will be handled for all elements of that type, even if they are added later via ajax. Note that I used h:body here as the element to delegate to but you can use any element that exists at document.ready time and is guaranteed to be an ancestor of all submit inputs.
If you have different ID or Name on them it's just to do somthing like
$(document).ready(function(){
$('#btn1, #btn2, #btn3').on('click', function(evt){
evt.preventDefault();
//your code
$(this).submit(); // or not submit, your choice
});
});
Try this thing
$(document).ready( function (){
$('input[type=submit]').click( function (){
// Whatever you want on submit button click option.
}
});
This will grab every submit button on the page and will bind click event to it, and this code will be called on any submit button click.

stop event propagation on element in jquery

I have an element as show below:
<div id="treeTable123" class="collapsed">
<div id="test"></div>
</div>
I have binded on click function to div with id 'test' using jquery.
function1:
$(document).delegate('#test', 'click', function(e){
....
});
I have another binded click function to other elements as:
function2:
$('[id^="treeTable"]').delegate('.collapsed', 'click', function(e){
});
When I click div with id 'test' both events are fired. So I want to prevent the event in the function 2 on clicking on event inside function 1. How can i do that?
$('[id^="treeTable"]').delegate('.collapsed', 'click', function(e){
if($(e.target).closest('#test').length === 0) {
// code placed inside this condition is not executed on clicking the element #test
}
});
Just call the e.stopPropagation() form the first callback. Here is a demo http://jsfiddle.net/eyXT7/2/.
you can simple use e.stopPropagation()
More Info
As you have it, its not possible. You can do it if you don't use delegation as the event has to bubble up to the delegate target for the event handler to fire. So function2 will fire before function1 and you can't prevent a it from firing after it fired.
$('#test').on('click', function(e){
e.stopPropagation();
....
});
http://jsfiddle.net/r5JaL/

jQuery click event not firing when appending new button

When I click the 'Show' button the show listener is invoked and a new hide button is displayed. But why is the hide button not invoked when I then click 'Hide' ?
$('.myCss').append('<input type="button" class="show" value="Show"/>');
$('.show').on('click', function () {
console.log('show clicked');
$('.myCss').append('<input type="button" class="hide" value="Hide"/>');
});
$('.hide').on('click', function () {
console.log('hide clicked');
$('.myCss').append('<input type="button" class="show" value="Show"/>');
});
It has to do with the order of elements being added to the page. If you drop the hide code within the show code it works (although you should check your logic):
$('.show').on('click', function() {
console.log('show clicked');
$('.myCss').append('<input type="button" class="hide" value="Hide"/>');
$('.hide').on('click', function() {
console.log('hide clicked');
$('.myCss').append('<input type="button" class="show" value="Show"/>');
});
});​
jsFiddle example
In your original code, the code to bind the click event to the hide button exists prior to the actual hide button, so it isn't actually bound to anything. By moving it within the other code block you delay the execution of that chunk. You could also use .on() to bind the click event to an event higher up in the DOM but it's really basically the same final result.
From the docs:
Event handlers are bound only to the currently selected elements; they
must exist on the page at the time your code makes the call to .on().
To ensure the elements are present and can be selected, perform event
binding inside a document ready handler for elements that are in the
HTML markup on the page. If new HTML is being injected into the page,
select the elements and attach event handlers after the new HTML is
placed into the page. Or, use delegated events to attach an event
handler, as described next.
Because when you set the event, the .hide element doesn't exist.
You could try setting the events like:
$('.myCss').append('<input type="button" class="show" value="Show"/>');
$('.myCss').on('click', '.show', function () {
console.log('show clicked');
$('.myCss').append('<input type="button" class="hide" value="Hide"/>');
});
$('.myCss').on('click', '.hide', function () {
console.log('hide clicked');
$('.myCss').append('<input type="button" class="show" value="Show"/>');
});
This attaches the click to the .myCss element (shich always exists), but only fires the function when the click was fired on .hide element inside it.
This solution is more efficent that creating the event everytime the element is created.
the problem is that you "hide" button does not exist when you try to define the onclick event on it.
I would suggest that you add it, set display=none, and then show it
When the '.hide' event handler is created, the 'Hide' button doesn't exist yet.
You could set up the event handler after creating the element, use event bubbling, or use use .live.
Several people have correctly answered that the hide button is created after the event is bound to the controls.
I suggest a different approach of using a handler at a higher level (document, in my example) that will attach to future controls (the current approach to the now deprecated .live).
Example:
http://jsfiddle.net/kQ2JA/1/
This will better match your expectations of binding the event to all current and future controls.

Categories