just a quick question. I'm having a problem with divs with onclick javascript within each other. When I click on the inner div it should only fire it's onclick javascript, but the outer div's javascript is also being fired. How can the user click on the inner div without firing the outer div's javascript?
<html>
<body>
<div onclick="alert('outer');" style="width:300px;height:300px;background-color:green;padding:5px;">outer div
<div onclick="alert('inner');" style="width:200px;height:200px;background-color:white;" />inner div</div>
</div>
</div>
</body>
</html>
Basically there are two event models in javascript. Event capturing and Event bubbling. In event bubbling, if you click on inside div, the inside div click event fired first and then the outer div click fired. while in event capturing, first the outer div event fired and than the inner div event fired. To stop event propagation, use this code in your click method.
if (!e) var e = window.event;
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
Check out the info on event propagation here
In particular you'll want some code like this in your event handlers to stop events from propagating:
function myClickHandler(e)
{
// Here you'll do whatever you want to happen when they click
// now this part stops the click from propagating
if (!e) var e = window.event;
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
}
This is a case of event bubbling.
You can use
e.cancelBubble = true; //IE
and
e.stopPropagation(); //FF
Just add this code :
window.event.stopPropagation();
return false; from the inner div's onclick function:
<div onclick="alert('inner'); return false;" ...
What you're dealing with is called event propagation.
One more way for webkit based browsers:
<div onclick="alert('inner'); event.stopPropagation;" ...
This worked for me in Jquery:
$('#outer_element').click(function(event) {
if(event.target !== event.currentTarget) return;
alert("Outer element is clicked")
});
This way, if the current target is not the same as the outer div, it will do nothing. You can implement normal functions on the child elements.
Here is some more reference to help you in understanding javascript event bubbling.
you have two 'div' and three '/div'.
This was very helpful, but it didn't work for me.
What i did is described here.
So I put a condition to the outer onclick event:
if( !event.isPropagationStopped() ) {
window.location.href = url;
}
You can use
$("divOrClassThatYouDontWantToPropagate").click(function( event ) {
event.stopPropagation();
});
//Using window.event.stopPropagation(), the parent div wont be clicked when the child div is clicked
//HTML
<div onclick="parent_func()">
<div onclick="child_func()"></div>
</div>
//JS
function parent_func(){
window.event.stopPropagation();
console.log('Parent')
}
function child_func(){
window.event.stopPropagation();
console.log('Child')
}
Related
I want to be able to activate an element's listener without activating the listener of the div that contains my element.
$('body').on('click', '.thiscoll', function(){
if (type === "form") {
hidePanels();
$('#navbar-pannel').show();
}
});
$('#main_container').on('click', 'a', function(){
hidePanels();
$('#custom-nav').show();
$('#l-name').html("New link name");
$('#l-destination').html("New link destination");
});
The first listener is on my div, while the second listener is on my links that are contained into my div. When I click on a link, it first triggers the 'a' listener, then the '.thiscoll' listener, while I only want to trigger the 'a' listener.
Is it possible?
Thanks.
Long story short, you want to stop event propagation. Something like
$('a').on('click', function(event) {
event.stopPropagation();
// and possibly do something else you require
});
should do.
Yes, what you want is possible. With events in Javascript we have this nice thing called event capturing and event bubbling. By default, browsers will register events in the bubbling phase.
For you, this means that the target you click will have its event handlers fired first. Then its parent's. Then its parent's parent's and so on. You can read more about it on MDN
To stop this propagation, you can use the stopPropagtion method on the Event-object. The Event object is supplied as the first argument in your event listener:
const main = document.querySelector('.main');
const button = document.querySelector('.button');
const stopPropagation = document.getElementById('stopPropagation');
main.addEventListener('click', () => console.log('Clicked on main'));
button.addEventListener('click', (evt) => {
if (stopPropagation.checked) {
evt.stopPropagation();
}
console.log('clicked button');
});
<input id="stopPropagation" type="checkbox">
<label for="stopPropagation">stopPropagation</label>
<div class="main">
Hello, World
<button class="button">Button</button>
</div>
Consider the following code as an example:
<div id="parent">
<div id="child">info goes here</div>
</div>
//javascript
function something{
//do something;}
//initial attempt
document.getElementById('parent').addEventListener('click',something);
//event capture
document.getElementById('parent').addEventListener('click',something,true);
When I click on the parent element I would like it to do something, and when I click the child I want it to do nothing. The problem is that when I click in the child element it is triggering 'something'.
I thought that it may be event bubbling, such that if I clicked on the child element, the event would bubble up from there to the parent. So then I was thinking about an event capture, but that also causes this problem.
Any advice or suggestions on how to accomplish this would be greatly appreciated.
Instead, check if the element originating the event Event.target - was indeed the desired element.
PS: Don't confuse with Event.currentTarget which (in contrast) is always the Element who has the Event handler attached.
function something (evt){
if (evt.target !== this) return; // Do nothing
// else...
console.log(`#${this.id} clicked`);
}
const el_parent = document.getElementById('parent');
el_parent.addEventListener('click', something);
// Example why you should not use `Event.stopPropagation()`...
document.body.addEventListener('click', () => console.log("BODY is notified!"));
<div id="parent">
PARENT ELEMENT
<div id="child">CHILD ELEMENT</div>
</div>
Don't use Event.stopPropagation()
Event.stopPropagation() would be an idea, but a bad one, since we should avoid an application to (at some layer) prevent an event to bubble - and eventually notify other elements that such an event happened. Imagine your body listens for click events to close custom select dropdowns... If you have elements wandering around your app, and that use Event.stopPropagation() - clicking on such element an opened dropdown will not close - resulting in broken UI. And this was just a simple example.
Use event.stopPropagation to stop event bubbling:
function something() {
console.log("something");
}
document.getElementById('parent').addEventListener('click', something);
document.getElementById('child').addEventListener('click', e => e.stopPropagation());
<div id="parent">
Parent info goes here!
<div id="child">Child info goes here!</div>
</div>
It is event bubbling. Just because you are handling the click event on the child, does not mean it stops bubbling to the parent.
There are two approaches to this. The first one is to stop the event from propagating like this:
document.getElementById('child').addEventListener('click',(e) => { e.stopPropagation(); something() },true);
The second is to check the event target and only run something when the deepest element that caused the click event is the child element:
document.getElementById('child').addEventListener('click',(e) => { e.target.id == "child" ? something() : nothing() },true);
I'm trying to put a listener on every tag "a". Here the example: http://fiddle.jshell.net/w5unvaxt/
function callback(e) {
var e = window.e || e;
/*
if (e.target.tagName !== 'A')
return;
*/
alert('The link is: ' + e.target.href);
}
if (document.addEventListener){
document.addEventListener('click', function (event) {
event.preventDefault();
callback(event);
});
}else{
document.attachEvent('onclick', function (event) {
event.preventDefault();
callback(event);
});
}
<!-- Works -->
my text
<!-- not works -->
<a href="http://www.example.com">
<div>my div</div>
</a>
The first example works good but not the second. How can I solve this issue?
The reason your code doesn't work is because the target element being clicked is the div not the a. This means that e.target.href is undefined for the div.
Using event delegation in plain JS is quite difficult. Just looking at the source code of a small library that accomplishes kinda what you want, I can see that it loops through the targets and if the target does not match the specified it assigns target to target.parentNode.
I would recommend using a small library like the ones I have linked (or event jQuery!).
You could use event delegation.
Event delegation allows you to avoid adding event listeners to specific nodes; instead, the event listener is added to one parent. That event listener analyzes bubbled events to find a match on child elements.
Here is an article on how event delegation works.
And the following is my example of how to use event delegation in plain JS.
// Get the parent DIV, add click listener...
document.body.addEventListener("click", function(e) {
// e.target was the clicked element
if(e.target && e.target.nodeName == "A") {
alert(e.target.innerText);
}
});
Link text
This way you only have to attach on event listener to the parent.
I have two elements, like this:
var parent = document.getElementById("el");
var child = parent.children[0];
and then a eventListener:
parent.addEventListener("click", function() {
alert("Hello World!")
});
and the problem is that when you click the child, the parents click event will be fired.
I want only when you click on the parent to fire the alert, not when you click on the child.
I am not using JQuery and won't.
I have searched on google, and all results uses e.stopPropogation which is JQuery.
So what's the best way to do this in plain JS?
Thanks alot.
You need to prevent event bubbling up to the parent element. For this you have to bind one more event handler to the child element:
child.addEventListener("click", function(e) {
e.stopPropagation();
});
Click event bubbles which means that event travels up DOM tree from child to parent unless its propagation is stopped.
You can check the ID of the clicked element and use that to control the trigger:
http://jsfiddle.net/nccjgtp6/
<div id="el">
This is a thing.
<div id="el2"> This is a second thing. </div>
</div>
var parent = document.getElementById("el");
var child = parent.children[0];
parent.addEventListener("click", function(e) {
console.log(e);
if(e.srcElement.id == 'el') {
alert('Hello world');
}
});
I do not know if this will work consistently in all browsers, but works for me in Chrome.
If I'm not mistaken, it's the event.stopPropagation(); line of code you need.
Suppose I have:
<div id="outer" onclick="thingsHappen()">
<div id="inner"></div>
</div>
When I click on outer or inner div, thingsHappen() is executed. That is obvious.
Now I have got a need to define a different method for the inner div.
For example
$("#inner").click(function() {
doThings();
});
When I click on inner both thingsHappen() and doThings() executes.
How do I execute doThings() when I click on inner div without executing thingsHappen()?
I tried to unbind click method from #inner, but it did not work.
PS. I cannot change the structure of HTML.
Stop the propagation of the event:
$("#inner").click(function(e) {
doThings();
e.stopPropagation();
});
Example: http://jsfiddle.net/QNt76/
JavaScript events bubble up the DOM tree unless you stop them from propagating. This is what was causing the parent event handler to get notified.
You want Event.stopPropagation():
$("#inner").click(function(e) {
doThings();
e.stopPropagation();
});
Events pertaining to a child element bubble up to parent elements in the DOM unless propagation is stopped like so:
$("#inner").click(function(event) {
doThings();
event.stopPropagation();
});
Here is a good read on capturing/bubbling and Javascript events. http://www.quirksmode.org/js/events_order.html
$("#inner").click(function(e) {
e.stopPropagation();
doThings();
});
What you are trying to do is stop the event (click) from "bubbling" up. In this case, you would want to stop the propagation of the event in the bubbling phase. If you are using jquery, you can use this function:
HTML
<div id="outer" onclick="thingsHappenOuter()">
<div id="inner">
</div>
</div>
JS
$("#inner").click(function(event) {
event.stopPropagation();
// do something
});
SEE: http://api.jquery.com/event.stopPropagation/ for more information.
You have to stop the propagation to the Document Tree:
$("#inner").click(function(event) {
doThings();
event.stopPropagation();
});
See: http://api.jquery.com/event.stopPropagation/
Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.