Keep the event, but avoid on links(or inner content) - javascript

This is probably asked a thousand of times, but I can't find an answer...
Here is an example:
var div = $('.div');
div.on('click', function(e) {
e.stopPropagation();
e.preventDefault();
div.toggleClass('red');
});
.div {
width: 50vh;
height: 50vh;
background: #eee;
}
.red {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="div">
link
</div>
The problem: event triggered when link(any content) is clicked.
I want remain the event, but avoid when content is clicked/selected/whatever. What are my options here?
Thanks

You just need to set up a "click" event handler for any child element of the div.div that prevents that event from bubbling up to any ancestor elements. This can be done with the * (universal) CSS selector.
Unless, you have reason to that you haven't described here, you don't need:
e.stopPropagation();
e.preventDefault();
in the div event handler.
var div = $('.div');
div.on('click', function(e) {
div.toggleClass('red');
});
// When any child element of the div with class .div is clicked...
$("div.div > *").on("click", function(evt){
// Don't allow the event to bubble up to the ancestor elements
evt.stopPropagation();
console.log("You clicked some child element of the div, but the event won't bubble up to it.");
});
.div {
width: 50vh;
height: 50vh;
background: #eee;
}
.red {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="div">
link
<span>Clicking me will do nothing</span>
</div>

Related

How to propagate event from element with higher z-index to elements under excluding click event?

I have a component which has markers in it. Marker is a styled div with icon. Markers have click, mouseenter and mouseleave events. When mouse enters tooltip appears. On top of markers I can place other element to cover them. That element has higher z-index. I still want to be able to hover over (mouseenter, mouseleave) over lower z-index elements (markers) while preventing click event on them when they are covered. Is there any solution to pass only few or exclude only some event from propagation on higher z-index element?
<!DOCTYPE html>
<style>
#elmHigherZindexID {
width: 100px;
height: 100px;
position: absolute;
background-color: chartreuse;
z-index: 1000;
}
#elmLowerZindexID {
width: 100px;
height: 100px;
position: absolute;
background-color: cornflowerblue
}
</style>
<body>
<div id="elmHigherZindexID">HIGH</div>
<div id="elmLowerZindexID">LOW</div>
</body>
<script>
let highElmRef = document.getElementById('elmHigherZindexID');
let lowElmRef = document.getElementById('elmLowerZindexID');
highElmRef.addEventListener('click', highEventHandler);
highElmRef.addEventListener('mouseenter', highOtherEventHandler);
lowElmRef.addEventListener('mouseenter', lowEventHandler);
function highEventHandler(event) {
event.stopPropagation();
console.log('high', event);
}
function highOtherEventHandler(event) {
event.stopPropagation();
console.log('high', event);
const cusEvent = new MouseEvent('mouseenter', {
view: window,
bubbles: true,
cancelable: true
});
lowElmRef.dispatchEvent(cusEvent);
}
function lowEventHandler(event) {
event.stopPropagation();
console.log('low', event);
}
</script>
</html>

Why the event trigger immediately when I just dispatch it?

I would like do something when i click element #b then dispatch an other event listener before handleB() finished
When I was clicked #b the event click on #a has dispatch successful and it has also triggered but I don't wanna trigger it
What's going on here??
document.getElementById('b').addEventListener('click', handleB)
function handleB() {
alert('Handle B!');
document.getElementById('a').addEventListener('click', handleA)
}
<div id="a">
AAA
<div id="b">BBB</div>
</div>
This is happening because of the event of #b bubbles up to #a and since you have added the click event listener inside handleB. It triggers immediately with the event of #b. You have to stop the event to bubble up. Below is the working example:
document.getElementById('b').addEventListener('click', handleB);
function handleB(event) {
event.stopPropagation();
console.log('b clicked');
document.getElementById('a').addEventListener('click', handleA)
}
function handleA() {
console.log('a clicked');
}
#a {
width: 200px;
height: 200px;
background-color: red;
}
#b {
width: 100px;
height: 100px;
background-color: green;
}
<div id="a">
<div id="b"></div>
</div>

multiple div's display content with click, prevent event bubbling

I have 3 div's: div1, div2, div3. When the user clicks on each div, I want to console log the content of that particular div only. I read about event bubbling and understood that the click event of the child will also be registered at the parent level. I tried the below code but couldn't get it to work correctly.
$(document).ready(function() {
$('#parent').on('click', 'div', function() {
console.log($(this).text());
})
})
#div1 {
width: 300px;
height: 200px;
padding: 25px;
background-color: red;
text-align: center;
}
#div2 {
width: 250px;
height: 150px;
background-color: blue;
padding: 25px;
text-align: center;
}
#div3 {
width: 200px;
height: 100px;
background-color: green;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div id="parent">
<div id="div1">div1
<div id="div2">div2
<div id="div3">div3</div>
</div>
</div>
</div>
</body>
How can I make it to print div1 when I click div1, div2 when I click div2 and div3 when I click div3?
is jQuery text() the right method to print the content? I can see it is printing spaces and all
The issue is not just related to event bubbling, but also the fact that the text() of an element contains the text of itself and all its child elements.
To do what you require you would need to filter() the contents() of the current element to retrieve only the text nodes - assuming you want to discard the text which is wrapped in any child element.
Try this:
$('#parent').on('click', 'div', function(e) {
e.stopPropagation();
var nodes = $(this).contents().filter(function() {
return this.nodeType == 3 && this.nodeValue.trim() != '';
});
console.log(nodes[0].nodeValue.trim());
});
Working example
Try this, according to this solution
$('#parent').on('click', 'div', function(e){
e.stopPropagation();
console.log($(this)
.clone()
.children()
.remove()
.end()
.text()
.trim()
);
})

Adding click event handlers recursively

I have an element #standardBox
#standardBox.click --> replaces itself with #newBox
#newBox.click --> replaces itself with #standardBox
But this latest #standardBox has no click event listener. I want it to have an on click event listener and its subsequently created elements too. This is getting into a recursive loop, which I don't know how to address.
I'm using this for header with standard contents, which gets replaced by something intermediate/new contents, which again is to get back to standard contents ...
Thanks.
HTML
<div id="container">
<div id="standardBox"></div>
</div>
CSS
html, body {
margin: 0;
padding: 0;
height: 100%;
}
#container {
position: relative;
height: 5em;
width: 5em;
background: #C5CAE9;
}
#standardBox {
position: absolute;
top: 20%;
right: 20%;
bottom: 20%;
left: 20%;
background: #ffffff;
cursor: pointer;
}
#newBox {
height: 3em;
width: 3em;
background: #000000;
cursor: pointer;
}
JAVASCRIPT
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>
$('#standardBox').click(function(){
$('#container').html('<div id="newBox"></div>');
// register event handler for new element created
$('#newBox').click(function(){
$('#container').html('<div id="standardBox"></div>');
// but this #standardBox has no click event listener
});
});
http://codepen.io/anon/pen/YPLKLq
Attach the handler to the body instead like this:
$("body").on("click", "#standardBox", function(){
$('#container').html('<div id="newBox"></div>');
})
.on("click", "#newBox", function(){
$('#container').html('<div id="standardBox"></div>');
});
This causes the body to listen for events that come from #standardBox and #newBox. Note that the this variable is still set to either the #standardBox or the #newBox element.
use below code. dynamically created element dose not fire event using 'click' function. you need to Attach the handler to the document( body )
$(document).on('click','#standardBox',function(){
$('#container').html('<div id="newBox"></div>');
// register event handler for new element created
});
$(document).on('click','#newBox',function(){
$('#container').html('<div id="standardBox"></div>');
// but this #standardBox has no click event listener
});
Why you are writing such complex code to do it. As there can be a very simple code.
Lets say this your html.
<div id="container">
<div id="standardBox"></div>
</div>
Now, to change the inner container.
$(function(){
$('#container div').click(function(){
$(this).attr("id")=="standardBox"?$(this).attr("id","newBox"):$(this).attr("id","standardBox");
});
});

Why `event.preventDefault()` is not working for two nested divs?

function clickOut(event) {
event.preventDefault();
alert('click on out');
}
function clickIn(event) {
event.preventDefault();
alert('click on in');
}
#out {
width: 100px;
height: 100px;
border: 1px solid red;
}
#in {
width: 50px;
height: 50px;
border: 1px solid blue;
}
<div id="out" onclick="clickOut(event)">
<div id="in" onclick="clickIn(event)">
</div>
</div>
Live demo: http://jsbin.com/qomuteyoke/1/edit?html,css,js,output
Why when I click on the inner div, there still pops two alerts, even if I've called event.preventDefault()? First is click on in, and 2nd is click on out?
Try using event.stopPropagation():
jQuery def:
Description: Prevents the event from bubbling up the DOM tree,
preventing any parent handlers from being notified of the event.
MDN def:
Prevents further propagation of the current event.
function clickIn(event) {
event.stopPropagation();
alert('click on in');
}
It's because there is no default action to prevent. Prevent default will work on anchor tags, which are used to prevent the default behaviour. What you want to do is to stop the propagation of the click, so it doesn't bubble up from the inner div. That way, if you click on the inner div, only the inner div click fires.
Replace your event.preventDefault() with event.stopPropagation().
Prevent default does not stop the event from propagating to the parents. You want to use event.stopPropagation(); which prevents further propagation of the current event. MDN
function clickOut(event) {
event.stopPropagation();
alert('click on out');
}
function clickIn(event) {
event.stopPropagation();
alert('click on in');
}
#out {
width: 100px;
height: 100px;
border: 1px solid red;
}
#in {
width: 50px;
height: 50px;
border: 1px solid blue;
}
<div id="out" onclick="clickOut(event)">
<div id="in" onclick="clickIn(event)">
</div>
</div>
css

Categories