Prevent nested elements from triggering an event for parent element - javascript

Structure:
.parent (has if/else to toggle on click) -> .child (has nothing)
<div class="parent">Parent
<div class="child">Child</div>
</div>
The parent element is styled to hide overflowing content and toggle its height on click. When the user clicks, the parent element will expand to show the child element. I want users to be able to click on the child element without the parent element toggling back to its original size and hiding the child element. I want the toggle to only happen on the parent.
I realize the child element is still contained within the parent element's clickable area, but is there a way to exclude it?

Solution 1: Compare target with currentTarget:
$("#parentEle").click( function(e) {
if(e.target == e.currentTarget) {
alert('parent ele clicked');
} else {
//you could exclude this else block to have it do nothing within this listener
alert('child ele clicked');
}
});
Fiddle
e.target will be the element that started the event.
e.currentTarget will be where it currently is (bubbling up) which will be parentEle in this click event as that's what this is listening for.
If they are the same, you know the click was directly on the parent.
Solution 2: Stop the propagation before the event hits the parentEle:
The other option is to prevent the event from bubbling up in the first place if there is a click on a child element. That can be done like this:
$("#parentEle").click( function(e) {
alert('parent ele clicked');
});
$("#parentEle").children().click( function(e) {
//this prevent the event from bubbling to any event higher than the direct children
e.stopPropagation();
});
Fiddle
The main difference between the two is that the first solution will just ignore the event in this listener and allow it to keep bubbling up. This may be necessary if you have a parent of this parentEle that needs to get the event.
The second solution stops any click events from bubbling past parentEle's direct children. So if there was a click event on a parent of parentEle, they would never see these events either.

Use event.stopPropagation();:
$('#a').add('#b').click(fun1);
function handler(event) {
event.stopPropagation();
// now do your stuff
}

Related

Updating a variable that holds number of "divs" when a new div gets added

As the title reads, is there a way to update the variable (which links to how many divs there is in a parent)?
The code I have works, but I was looking for another way...
The code I have:
function addDiv() {
//adds a div into the parent
}
parent.addEventListener("mouseover", ()=>{
getAllLists = parent.querySelectorAll(".list-name-tile")
getAllLists.forEach(list => {
list.addEventListener("click", ()=>{
//other code
})
});
})
In my code, I used "mouseover" to update getAllLists; I was just wondering if there was another way to do this and achieve a similar effect or is this the way to it best? Please ask me to clarify or if you need additional information.
Thank you!
Retrieving the div elements in the mouseover event listener is ok in my opinion.
However, there is a problem in your code. Each time you hover over the parent element, the click eventlistener is attached to the child elemens over and over again. You can try this by inserting a console.log() in the click event handler. Hover over the parent element a few times and then click on a child element. You will see the output of the console.log a few times.
This is because the clicker event listener is attached everytime you hover over the parent element.
Possible solution
As far I understand your question you would like to add a click eventlistener to all child element (even the ones which are added dynamically). If thats the case you can make usage of Event Delegation.
Bubbling also allows us to take advantage of event delegation — this concept relies on the fact that if you want some code to run when you select any one of a large number of child elements, you can set the event listener on their parent and have events that happen on them bubble up to their parent rather than having to set the event listener on every child individually. Remember, bubbling involves checking the element the event is fired on for an event handler first, then moving up to the element's parent, etc.
A good example is a series of list items — if you want each one to pop up a message when selected, you can set the click event listener on the parent , and events will bubble from the list items to the .
Event bubbling and capture (scroll down to the section "Event delegation")
Via Event Delegation you can do it this way:
HTML
<div id="parent">
<div class="list-name-tile">First div</div>
<div class="list-name-tile">Second div</div>
</div>
JavaScript
const parent = document.getElementById("parent");
parent.addEventListener("click", e => {
if (e.target.classList.contains("list-name-tile")) {
// Do stuff
}
});
function addDiv() {
const div = document.createElement("div");
div.classList.add("list-name-tile");
div.textContent = "Next div";
parent.appendChild(div);
}
addDiv();
In the example I have attached a click event listener to the parent element. So whenever you click on a child element the event is "bubbling" to the next ancestor which is your parent element. There we have the event listener and can handle it. In the example I have filtered it to only do something when the element, which has triggered the event, has a specific class. You can also filter for specific events and so on.

Preventing a JQuery click listener

I have a .click() on a div.
I added a button in the div and now every time I click the button, the JQuery does the function associated with the div and preforms the action on the button.
I understand why it is doing this. I was wondering if I could make the click listener ignore the children?
Is there already a function/syntax for that or do i need to make one from scratch? The div and the button are called by #id.
To make the event listener ignore children, you can check that the bound element is the same as the target
$('div').on('click', function(e) {
if ( e.target === this ) {
// DIV was clicked, not children
}
});
Or go the other way, preventing the event from bubbling up
$('div button').on('click', function(e) {
e.stopPropagation();
});

Observing click of element within element that has a separate click observe function

I have an element within another element and both have separate click functions. What I would like to do is ignore or stop the parent element if the child element has a click function. For example:
<div class="parent">
<div class="child1">Child Click Function</div>
Parent Click Function
</div>
<script type="text/javascript">
document.observe('dom:loaded',function(){
if ($$('.parent') != undefined) {
$$('.parent').invoke('observe','click', function(e) {
alert('parent');
});
}
if ($$('.child1') != undefined) {
$$('.child1').invoke('observe','click', function(e) {
alert('child');
});
}
});
</script>
What happens is that when child1 is clicked, both that and parent are triggered since child1 is within parent. I would like disable/stop the observe when child is selected, but when you click on anything else inside parent, it works as it should.
Thanks.
You're encountering what's known as "event bubbling". Events on a given element bubble up the DOM until they reach the root node unless you explicitly stop the bubbling. Since it looks like you're using Prototype, updating your child's event handler to the following should do the trick:
$$('.child1').invoke('observe','click', function(e) {
Event.stop(e);
alert('child');
});
http://api.prototypejs.org/dom/Event/prototype/stop/
I'm not sure which one works, but I usually use both:
if (event.cancelBubble)
event.cancelBubble();
if (event.stopImmediatePropagation)
event.stopImmediatePropagation();
And pass the click event into the onclick function.
Both stop propagation and cancel bubble will stop the propagation of the event all together ,
from what I get is you want to bypass the event associated with the parent.
I would suggest to use .unbind() on the parent in case the child is clicked. For example,
(CHECK CHILD CLICK) {
$('.parent').unbind('click');}

How to disable click events on a parent DOM object without disabling click events on its child DOM object?

I have some HTML like this:
<a class="button">
<span>
<span>
<span class="buttonspan">Content</span>
</span>
</span>
</a>
I already have some events on the parent Anchor object. Now I am trying to add a click event on to the child span element and at the same time to disable click events on the parent Anchor object. I am using jQuery to achieve this, but I could not figure out. My jQuery code is like this:
$('a.button').click(function(event){
return false;
});
$('.buttonspan').live('click', function(event){
event.preventDefault();
event.stopImmediatePropagation();
// some function
});
If I execute the code above, it prevents the child element click event as well. But if I do not the first part, the parent click event will be triggered as well. Is there a way to disable the parent event without disabling the newly added child click event?
You could set the click event on the parent button and use the event target to determine what was clicked and perform the necessary actions.
$('a.button').click(function(e) {
var $target = $(e.target);
if ($target.is('.buttonspan')) {
// do actions for the .buttonspan click
} else {
// do actions for a click anywhere else inside a.button
e.preventDefault();
}
});

Javascript MouseOver / MouseOut children events

I have an element with some child elements. When the mouse leaves the parent element I want to hide the parent and it's children. Problem I'm having is that when I hover over any of the children, the mouseout event is being fired. What's the best way to prevent this? I really only want the event to fire when the mouse is not within the parent or any of it's children.
The event is bubbling up from the child to the parent (where it is being caught)
You should catch the event on the children by adding a listener and making the propagation stop there.
This code will stop the event from bubbling up to the parents handler
function onMouseLeave(e)
{
if (!e) var e = window.event;
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
}
question: The mouse off event is fired by the parent, when it should not. Mouseing over the child should not trigger a mouse off from the parent. How can we stop this?
You only need a mouseout handler attached to the parent element. But...
You need to check that the parent is actually the target of the mouseout event, as opposed to the event bubbling up from one of the children. Check event.target (W3C) and event.srcElement (IE).
You also need to check that the element that the mouse will be entering is not a descendant of the parent. Check event.relatedTarget (W3C) and event.toElement (IE).
From http://api.jquery.com/mouseover/:
mouseover fires when the pointer moves into the child element as well, while mouseenter fires only when the pointer moves into the bound element.
and the same goes for mouseout vs mouseleave

Categories