Javascript useCapture click event handler not triggering on button with image - javascript

I encounter this a lot, and normally fix it with a hack by adding the style "pointer-events: none" to the children of the button. However once and for all I would like to understand why this code does not work.
For example this answer says:
Example <div> <ul> <li></li> </ul> </div> In the structure above, assume that a click event occurred in the li element.
In capturing model, the event will be handled by the div first (click
event handlers in the div will fire first), then in the ul, then at
the last in the target element, li.
If I try the quoted example above, all I ever see is the <li> event handler occuring, not one for the <li> and <div>
Say I have a button with an image. If one clicks the button, its runs the event handler, if one clicks the image on the button it does not run the event handler. Okay that is understandable, except I have specified useCapture = true in the event handler, so I expect the event handler to start capturing at the root html element, and work its way down to the actual element that was clicked (which is interrupted by the preventDefault() below)..
function working(event) {
if (event.target.id == "BUTTON") {
alert("Its working!")
event.preventDefault();
}
}
document.addEventListener('click', working, true);
<button id="BUTTON" type="button">
<img src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png">
Works on text but not image</button>
I keep reading about bubbling vs capture, and I think I understand it, but clearly I don't because the code I write doesn't work.

This is because you use event delegation, so the capturing is done on document. useCapture makes no sense here.
One solution is to use closest on evt.target to retrieve the first parent with id #BUTTON and act on it.
See also
function working(event) {
if (event.target.closest("#BUTTON")) {
alert("Its working!");
}
}
document.addEventListener('click', working);
<button id="BUTTON" type="button">
<img
src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png">
Works on text but not image</button>
Another solution is to add the listener to the element itself (using [useCapture = ]true). In that case the capturing starts on the element the event listener is added to.
function working() {
alert("Its working!");
}
document.querySelector(`#BUTTON`).addEventListener('click', working, true);
<button id="BUTTON" type="button">
<img
src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png">
Works on text but not image</button>

here you have double equals sign
(event.target.id == "BUTTON")
there only has to be one and it works
(event.target.id = "BUTTON")

Related

Button inside a span, both have an event. If I click the button, the span event also starts

<span onClick={'event example 1'}>
content example 1
<button onClick={'event example 1'}>
content example 2
</button>
</span>
How can I press the button without also involving the span event? It's possible?
Working example. you have to bind event to get access to stop event.stopPropagation()
function spanFunction(e) {
console.log('spanFunction')
}
function buttonFunction(event) {
event.stopPropagation()
console.log('buttonFunction')
}
<span onClick="spanFunction(event)">
content example 1
<button onClick="buttonFunction(event)">
content example 2
</button>
</span>
there are two extra properties to handle this issue:
event.preventDefault is to prevent the default action of the
element.
event.stopPropagation is to stop the event from propagating
upwards.
In your handler specify first attribute - event and in html bind the function with event. In this case you need to use stopPropagation.
onClick(function(event){
event.stopPropagation();
console.log('button element');
});
Events bubble by default. So the target is the element that triggered the event (e.g., the user clicked on).
If u face some ambiguity while stopping the event bubbling via stopPropogation(preferred) u can this structure.
// Dont forget to pass event (e).
if (e.tagName.toLowerCase() === 'button') {
conosole.log('CLICK');
}

Event is firing Two times

Hi I am binding onclick event to parent as well as child (same method). Event is getting fired two times How to avoid this?
<div id="sparentId" onclick="javascript:somemethod()" >
<button id="childId" onclick="javascript:somemethod()"></button>
</div>
Onclick of Div the event is getting fired two times.
Try:
<button id="childId" onclick="javascript:somemethod(event)"></button>
JS code
function somemethod(event){
event.stopPropagation();
}
The reason that the onclick event is showing twice, is because there is something called event bubbling in JavaScript.
Take a look at the following:
This image shows that, if the <img> was clicked, the event would "bubble" up to the <p> tag, then to the <div>, then to the rest of the document. If there was an onclick event on the <p> tag, and even if the <p> tag was not clicked (but the <img> was), the event would necessarily "bubble" all the way up the DOM, and would still continue when an event was fired on the <p> tag (in other words, if you also had an onclick event on the <div>, then that would fire as well.
So what you should do is this:
<div id="sparentId" onclick="javascript:somemethod()" >
<button id="childId"></button>
</div>
In other words, as I explained above, you wouldn't need the extra onclick event handler in your button anymore, because when your button is clicked, the event bubbles up to the parent div, which would fire that event.
If you want to use your original HTML code, that's fine as well - just add this:
function somemethod(evt) { // the method you run
// some code
evt.stopPropagation(); // stops bubbling
}
This effectively stops the event from bubbling up your DOM tree.
It is getting called twice because you are calling it twice, i.e. once in the div click and once in the button click. the button is already inside the div.
<div id="sparentId" onclick="javascript:somemethod()" >
<button id="childId" onclick="javascript:somemethod()"></button>
</div>
try
<div id="sparentId">
<button id="childId" onclick="javascript:somemethod()">Click Me</button>
</div>
use
event.stopImmediatePropagation()

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.

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.

Prevent javascript onclick on child element

Ok, simple question:
<div onclick="javascript:manualToggle(this)">
<span>Allowed to click</span>
<span>Not allowed to click</span>
<span>Allowed to click</span>
</div>
Without replicating the manualToggle on to the 2 spans that are allowed to click, how can I prevent the "Not allowed to click" span from firing it's parent div onclick event when it is clicked on?
Give the span an id an attach onclick event to it and use
A jQuery sample
$("#spn2").click(function(event){
event.stopPropagation();
});
event.stopPropagation(): Stops the bubbling of an event to parent elements, preventing any parent handlers from being notified of the event.
It would make sense to use a library but without you can try this (edited with an entire page to test):
<html><head></head>
<body>
<script type="text/javascript"><!--
function manualToggle(val)
{
alert(val.id);
}
--></script>
<div id="test" onclick="manualToggle(this);">
<span>Allowed to click</span>
<span onclick="event.cancelBubble=true;if (event.stopPropagation) event.stopPropagation();">Not allowed to click</span>
<span>Allowed to click</span>
</div>
</body>
</html>
You need an event handler (it's very easy to do this in something like jQuery) that catches clicks for the spans within the div and only fires the function if, for example, the span has/hasn't a particular class.
I just had the same issue and could not get jQuery to work so I used simple Javascript:
document.getElementById("your_span").addEventListener("click", (event) => {
event.stopPropagation();
});
That did the trick for me. Obviously you need to add the addEventListener to every Element you wanna apply this to. Since I do a lot of DOM manipulation this was not an issue for me.
Hope this helps anyone :)
with mootools you can use the method stopPropagation:
$('myChild').addEvent('click', function(ev){
ev.stopPropagation(); // this will prevent the event to bubble up, and fire the parent's click event.
});
see http://mootools.net/docs/core/Native/Event#Event:stopPropagation
also see this very similar question: How can I stop an onclick event from firing for parent element when child is clicked?
Possible solution: give the span's id's and check whether the clicked id is allowed to be clicked in your function
bad idea: you don't know which span is clicked since you call the function from your div...
<div onclick="manualToggle(this)">
<span>Allowed to click</span>
<span>Not allowed to click</span>
<span>Allowed to click</span>
</div>
<script>
function manualToggle(cur){
if(cur !== event.target) return false;
//CODE
}
</script>
Here we have set a click event on div tag,
and we are passing the current element(div) as parameter
inside the manualToggle function you have the element in params where you have set the event,
inside the function we have event (a global var object), where you can get the clicked element (event.target),
if the clicked element is not same(equal) to the element where we have set the event then do nothing.
there are some other methods are also available, use stopPropagation
https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation

Categories