Element on element gets clicked both by Javascript - javascript

I've got a div which has multiple elements nested. If I press on the div, the buttons appear in the same DIV. If I press on the button however, the buttons dissapear as well (this is because of a toggleClass on the div)
I've tried returning but that isn't working as well. See below for a JSFiddle
http://jsfiddle.net/p168uLv2/
$(document).on('click', "[data-link=level1]", function() {
console.log("li clicked");
$(this).find(".knoppenbalk").toggleClass("displaynone");
});
$(document).on('click', "[data-link=solo]", function() {
console.log("solo BUTTON clicked");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-link="level1" class="limodeknop">
<div class="overlay"></div>
<div class="modeknop">
<div class="titel">
<lrmodenaam>Level 1</lrmodenaam>
<lrsubmode>Tutorial</lrsubmode>
</div>
<div class="knoppenbalk displaynone">
<div data-link="solo" class="solo btn">Solo</div>
</div>
</div>
</div>
This is made with jQuery, and I'm working with Framework7, but I don't think thats an issue.

You should stop the propagation of the events (calling bubbling). You can search tons of articles about it.
http://jsfiddle.net/p168uLv2/1/
$(document).on('click',"[data-link=solo]", function(e){
console.log("solo BUTTON clicked");
e.stopPropagation();
});
This only apply to the child element, to avoid the parent click propagation.

You can stop an event propagating to parent elements with use of:
event.stopPropagation();
You will want to accept event as an argument to your inline functions.

$(document).on('click',"[data-link=solo]", function(e){
e.stopImmediatePropagation();
console.log("solo BUTTON clicked");
})
;

Related

Event propagation issue

I have a series of click events which are causing me some propagation issues. The data for this container is loaded in via ajax hence the body on click method. Here's the code I have:
$(function () {
$("body").on("click","#top-div",function(){
console.log("top event");
});
$("body").on("click","#middle-div",function(e){
e.stopPropagation();
});
$("body").on("click","#bottom-div",function(){
console.log("bottom event");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="top-div">
top
<div id="middle-div">
middle
<div id="bottom-div">
bottom
</div>
</div>
</div>
The top div has an event which the middle one needs to not inherit hence the stopPropagation(). However the bottom one needs to have an event of its own but the stopPropagation() from the middle one is stopping it from executing the event (if I remove the stop propagation the bottom event triggers but coincidentally so does the top)
How can I get around this bubbling issue?
I think what you want to happen is that the propagation is only stopped if it originated from the middle div; if it originated from the bottom div you want the event to bubble all the way to the top.
You need to call stopPropagation conditionally. If the event did not originate on or inside #bottom-div, you want to call it. You can test for this using closest:
if (!$(e.target).closest('#bottom-div').length) {
e.stopPropagation();
}
It is better to use closest for this, rather than testing the element's id directly, because with closest it will continue to work as expected even if there are other elements (a or em, for example) within the various divs.
$(function () {
$("body").on("click","#top-div",function(){
console.log("top event");
});
$("body").on("click","#middle-div",function(e){
if (!$(e.target).closest('#bottom-div').length) {
e.stopPropagation();
}
});
$("body").on("click","#bottom-div",function(){
console.log("bottom event");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="top-div">
top
<div id="middle-div">
middle
<div id="bottom-div">
bottom
</div>
</div>
</div>
Bubbling works from most nested element to tree root, I think You misunderstanding it in some way. So for example click in bottom-div will:
call event on bottom-div --> call event on middle-div --> call event on top-div.
As I understand the need You want to some how check what div was clicked, so to have control on it just create single event and check clicked target like that:
$("body").on("click","#top-div",function(e){
if ( e.target.id ==='top-div'){
//click in top div
}
if ( e.target.id ==='middle-div'){
//click in middle div
}
if ( e.target.id ==='bottom-div'){
//click in bottom div
}
});
In this proposition You know exactly which div was clicked, but it will always be the most nested one, so target will be middle-div only when will be clicked part of middle-div which is not bottom-div, it will be for example padding space, the same is with top-div it will be target only if click will be in space without child elements.
More about event bubbling You can find in http://maciejsikora.com/standard-events-vs-event-delegation/.
Instead of attaching event to every div. You can consider doing it as follows
check this snippet
$(document).ready(function() {
$("body").on("click", "div", function(event) {
console.log(event.currentTarget.id + "event");
if (event.target.id === "middle-div") {
event.stopPropagation()
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="top-div">
hello
<div id="middle-div">
hi
<div id="bottom-div">
bott-mid-v
</div>
</div>
</div>
Hope it helps

How can I force to call dynamically added element,s onclick() first

<div id="outerDiv" onclick="javascript:addEvent()">
<div id="inner">
<a class='editEV' href="javascript:void(0)">event1</a>//*added dynamically from addEvent method.*
</div>
</div>
My script is:
$('#inner').on('click','.editEV',function(){
editEvent();
});
When I click on anchor addEvent() called first then editEvent(), but I want that when I click on div then addEvent() should call and when I click anchor then editEvent.
I am aware about bubbling so that's why I introduce an inner static div to bind listener, but still addEvent() calls first. I am unable to figure out how can I force to call editEvent first.
You are using both - inline event set ( onclick=.. ) and Jquery on. Choose one of them to have more clear code. I would choose jquery on, and solution for this problem is to create two events - one on div, second on edit element, but in second We need to stop bubbling by using e.stopPropagation method. Here full working example:
$(function(){
$("#outerDiv").on("click",function(e){
console.log("Add click");
});
$("#outerDiv").on("click",".editEV",function(e){
console.log("Edit click");
e.stopPropagation();//very important to stop propagate event
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="outerDiv" style="padding:20px; background:grey;">
<div id="inner">
<a class='editEV' >event1</a>
</div>
</div>
Without stopPropagation our event is going up to div and runs its event, stopPropagation avoids propagate event to upper elements.
You also use this if you don't want to alter your code.
$(function(){
$("#outerDiv").on("click",function(e){
addEvent();
});
$("#outerDiv").on("click",".editEV",function(e){
editEvent();
e.stopPropagation();
});
});
e.stopPropagation();
use this.
If you want to read more on .stopPropagation(), look here.

Accordion preventing click on link

I have an accordion with a link in it, but whenever I click on the link, the accordion thinks I'm trying to close it. It's set up so you can click anywhere on the accordion to open or close it which I would like to keep, but when I person clicks on the link, ignore the accordion behavior and follow the link instead.
<div class="wrap">
<div class="top"></div>
<div class="middle">
<h3>Always showing</h3>
<div class="hidden">
<p>I want to follow this link.</p>
</div>
</div>
<div class="bottom"></div>
</div>
$('.wrap').on(touchClick, function (e) {
if ($(this).hasClass('active')) {
$(this).removeClass('active');
$(this).find('.hidden').slideUp('fast');
return false;
}
$('.wrap').each(function (index, el) {
$(this).removeClass('active');
$(this).find('.hidden').slideUp('fast');
});
$(this).find('.hidden').slideDown('fast');
$(this).addClass('active');
});
Not tested but I believe this will work
$('.wrap').on(touchClick, function (e) {
//other code
});
$( "a" ).click(function( event ) {
event.stopPropagation();
});
It should stop the click from bubbling up and triggering the accordion events.
As an afterthought if you want use touchClick like youre accordion you could rewrite it as.
$( "a" ).on(touchClick, function (e) {
e.stopPropagation();
});
You will need to tell the browser to stop the event from bubbling up the event chain using event.stopPropagation() (see this so post for more details on this). This means that jQuery never gets to know about the click event, thus it won't close the accordion.
Add this in the specific link's click event listener and it should work as you want it to:
$('.wrap a').each(function(e){
e.stopPropagation(); // stop the event from bubbling up
});
However, don't confuse it with event.preventDefault(), which would not stop the event from bubbling up, but it would stop the browser from opening the link when it's clicked.

How to detect if a specific class link was clicked inside a DIV and override the DIV's click action then?

I have several DIV of the following kind on my page:
<div class='entry'>
This is a statement
<a title="Search #travel" class="app-context-link" href="">#travel</a>
</div>
When a DIV of class .entry is clicked I trigger the following:
$(".entry").on('click', function(e) {
console.log("DIV Clicked");
});
When a link of the class .app-context-link is clicked I trigger the following:
var context_links = document.getElementsByClassName('app-context-link');
for (var k=0;k<context_links.length;++k) {
context_links[k].addEventListener('click', function(e) {
console.log("The context link inside DIV is clicked");
});
}
The question:
Right now when I click on the app-context-link both actions seem to be triggered: for the DIV (because a .click event is detected) and for the link (because there's an event listener on a link of that class).
How do I make it that if the link is clicked the DIV on click jQuery is not triggered?
I tried several possibilities, nothing worked. Also I would prefer not to reorganize the code too much, but simply add some directive in the on click jQuery part so that it detects if a link was clicked and does not do what it would normally do if the DIV was clicked.
Thank you!
you can use like this
$(".entry").on('click', function(e) {
e.stopPropagation();
alert($(this).prop("tagName"));
});
$(".entry a").on('click', function(e) {
e.preventDefault();
e.stopPropagation();
alert($(this).prop("tagName"));
});
DEMO
Use stop propagation :
context_links[k].addEventListener('click', function(e) {
e.stopPropagation(); //Here
console.log("The context link inside DIV is clicked");
});
This will stop the click event from bubbling, so when you click on the a, click events of its ancestor will not trigger.

Click span inside jQuery button

Part of a bigger solution, I have accordion-type jQuery control that implements headers as jQuery toggle buttons. Each header also has to have a help balloon. In nutshell, the setup is similar to that posted at this jsFiddle .
<div id="button1">Go to main action <span id="span1" style="color:blue">Help</span> </div>
<div id="out"/>
$('#button1').button().click(function(){
$('#out').text('Button clicked');
});
$('#span1').click(function(){
$('#out').text('Span clicked');
});
Is that possible to make it so I can click on the Help span, which is located inside the button div? Or, will button always get the events for all of its content preventing inside elements from getting click events?
Thank you.
Your event first fires on span and then also on button. You can prevent the event to be fired on parent by stopPropagation() method. Also, return false do the same.
Fiddle for demonstration
$('#span1').click(function(e){
$('#out').text('Span clicked');
e.stopPropagation();
});
or:
$('#span1').click(function(){
$('#out').text('Span clicked');
return false;
});
jSfiddle http://jsfiddle.net/kxntf/5/

Categories