How to prevent event bubbling in javascript - javascript

thanks for reading... I'll get right into the issue.
I have an onclick function attached to an image.
<div id="mercury" onclick="displayCreations()">
Javascript function:
function displayCreations(){
document.getElementById("projects").style.display = "block";
}
The div I'm displaying as a block is set to none once you arrive at the page. This function sets the display to block, which works.
I'm having trouble with making an onclick function for an image inside the div that sets the display value back to none. This doesn't seem to work with my current code...
HTML:
<div id="mercury" onclick="displayCreations()">
<img id="exit" onclick="hideCreations()" src="./assets/images/exit.png" alt="exit button" title="Leave Planet: Mercury" />
<div id="projects">
<h3>No creator here, but it looks like you've found some his wonderous creations...</h3>
<ol>
<li>Project 1</li>
<li>Project 2</li>
<li>Project 3</li>
</ol>
</div>
</div>
Javascript:
function displayCreations(){
document.getElementById("projects").style.display = "block";
}
function hideCreations(){
document.getElementById("projects").style.display = "none";
}
When I run this site on google chrome and click the 'exit' button, nothing happens and nothing is displayed in the error messages.
This link leads you to a well-known site, Gyazo, where you can find a gif of what I see on my end.
Link: Link
I'd prefer a javascript solution for my current code, and perhaps you can explain to me why this is happening so I don't get into the same situation again.

It is caused due to event bubbling.Triggering an event on child propagates upward toward its parent.In your case click event on image also triggers click event on parent div.use event.stopPropagation() to prevent this from happening.
HTML :
pass the event as parameter to event listener function
<img id="exit" onclick="hideCreations(event)" src="./assets/images/exit.png" alt="exit button" title="Leave Planet: Mercury" />
JS:
Capture the event and call it's stopPropagation method
function hideCreations(event){
event.stopPropagation();
document.getElementById("projects").style.display = "none";
}

A very useful solution from AL-zami. It's also useful outside the function e.g. onclick="event.stopPropagation();yourFunction(existing parameterset)". So You don't need to change yourFunction and it's parmeterlist, nor the other calls of it in the code.
It's even possible to create an extra container (e.g. div) around different events to prevent bubbling. e.g.:
<div id="picBigOLL" onclick="previousPict();">
<div id="picBigPlay" onclick="event.stopPropagation();">
<div id="playButsBox">
<div id="bPPlayL" onclick="diaPB(-1)">
⯇
</div>
<div id="bPPlayS" onclick="diaPB(0)">
||
</div>
<div id="bPPlayR" onclick="diaPB(1)">
⯈
</div>
</div>
</div>

Related

How to execute js code again whenever a class name change?

Sorry for my editting format in advance cos it's been a long time since I asked a question. I will try my best to follow all the rules.
So I have this list which works like an image carousel:
<div class="carousel">
<ul>
<li class="past"><img src="img1.png"/></li>
<li class="past"><img src="img2.png"/></li>
<li class="current"><img src="img3.png"/></li>
<li class="future"><img src="img4.png"/></li>
<li class="future"><img src="img5.png"/></li>
</ul>
</div>
Whenever I click on an image, the clicked item's class name will change to "current" and I will translateX <ul> to make "current" <li> look "centered". All of these are in "carousel" <div>.
However I have another div which has a background of an empty-screen iPhone mockup:
<div class = "iphone_screen">
<div>
<img class="display" src="blank_screen.png"/>
</div>
</div>
and I want to do this to the "iPhone" <div>:
var imgUrl = $("body").find(".current").find('img').attr('src');
$(".display").attr('src',imgUrl);
But this jQuery will only be executed once when I load the page.
So how do I execute my jQuery code again whenever I lick one of the <li> items and make the class name current change?
Update: Thank you all for the replies! I feel so stupid......I don't know why I ask this question.........I added a click function before and it didn't work.Then I started to look for alternatives. Now when I think about it, the selector must be wrong.
Since the event that drives everything comes from a click on the li you could run on a click for any li's (inside a ul) inside the carousel classed div.
$(".carousel > ul > li").click(function () {
var imgUrl = $("body").find(".current").find('img').attr('src');
$(".display").attr('src',imgUrl);
});
put your code in a function.
$(".carousel li").on("click" ,function () {
var imgUrl = $("body").find(".current").find('img').attr('src');
$(".display").attr('src',imgUrl);
});

Click event only fires when element is placed in header

I've got a single-page app UI with a custom navigation script. The script works perfectly in a minimally styled test page, but when I bring it into the actual app UI, it starts getting wonky and the click events are not firing consistently the way that I'd expect them to.
I have click events bound to each of the links, but the events only seem to fire when the element is placed in the header.
The HTML
<header>
<a data-role="navigation" data-target-view="mainView">Home</a>
<a data-role="navigation" data-target-view="settings">Settings</a>
<a id="headerLink" data-role="navigation" data-target-view="detailsView">Details</a>
</header>
<section data-role="page">
<section id="mainView" data-role="view">
<section class="pageContent">
</section>
<footer class="pageFooter">
<a id="footerLink" data-role="navigation" data-target-view="detailsView">Details</a>
</footer>
</section>
<section id="detailsView" data-role="view">
<section class="pageContent">
</section>
<footer class="pageFooter">
</footer>
</section>
<section id="settings" data-role="view">
<section class="pageContent">
</section>
<footer class="pageFooter">
</footer>
</section>
</section>
Handler Registration
$(document).ready(function(){
$("[data-role='navigation']")
.unbind("click.cgt_pathfinder")
.bind("click.cgt_pathfinder",function(event){
alert("Triggered");
});
});
I've stripped out the actual navigation logic just to make this easier to follow.
The Issue
When I load the page, I've got a breakpoint set on my handler registration, and I can see all the elements retrieved by $("[data-role='navigation']"). I see 4 elements: The three links in the <header>, and the one solitary link in the .pageFooter section of #mainView.
You'll notice that (save for the ID attribute and their location on the page), #headerLink and #footerLink are identical.
When I click #footerLink, nothing happens. I know the element was picked up when I registered my event handler, so it should issue the "Triggered" alert message, but it doesn't.
I've also tried moving #footerLink around the document (pulling it up one layer at a time and testing at each stop. The event did not fire until the link was in the <header>
When I click #headerLink, the event fires exactly as expected. In this example, I receive the "Triggered" message, and in the actual app, I see a successful navigation event.
So, the question is: "What am I missing?" There's something different about #footerLink that's preventing the event from firing, but I'm at a loss.
Possibly typo and unbalanced tag
<section data-role="page">
<section id="mainView data-role="view"> // No (") for id
<section class="pageContent">
</section>
Near bottom of markup
</settings> // No opening tag for settings
</section>
Working jsfiddle
I have checked your case. But it is working fine for me.
Please replace your jQuery function with this:
$(document).ready(function(){
$("[data-role='navigation']").unbind("click.cgt_pathfinder").bind("click.cgt_pathfinder",function(event){
alert("Triggered = "+$(this).text());
});
});
Does your code dynamically update the #footerLink element ?
If this element gets added to the page by your code (e.g : through a $('.pageFooter').append(html)), you will need to bind back the click action to this new element.
Is there any other code (yours or some plugin's) which could alter the click event handlers in your page, but not in your header ?

slideDown function needs two click to work

I'm having a slideDown function on my site. But somehow it doesn't work the first time when you click it. So I need to click two times to make the function work. What can possible be wrong?
I also want the div to slide up when I click on the button again, don't know how I will do this. I tried using slideToggle but it just ended up with the div going up and down a couple of times before closing. Even for this I needed to click two times.
Here is my JS:
function showCart() {
$("#rollDown").click(function() {
$("#shopping_cart_page").slideDown();
});
/* not relevant for this */
emptyBag = document.getElementById("emptyBag");
emptyBag.addEventListener("click", emptyCart);
}
And here is my HTML:
<div id="navbar">
<ul>
<li>Products</li>
<li>About</li>
<li>Giveaways</li>
<li>Contact </li>
<li><a id="rollDown">Shopping Bag</a></li>
</ul>
</div>
Here's a simple example:
jQuery:
$(document).ready(function(){ // Just adding the click event inside the document ready method should do the trick for you.
$("#rollDown").click(function() {
$("#shopping_cart_page").slideToggle();
});
});
HTML
<input type="submit" id="rollDown" value="Toggle"/>
<div id="shopping_cart_page">Hi</div>
Fiddle: http://jsfiddle.net/64gn1unk/

Cannot give .focus() to an element of a dropdown menu

Here is a Boostrap navigation bar, containing a dropdown menu, containing itself an <input>.
When I click on the dropdown menu, it is succesfully displayed. The value of the <input> is successfully changed to Bonjour but this <input> doesn't get the focus. Why ?
http://jsfiddle.net/rzsmdg4f/1/
How to give the focus to a input contained in a dropdown menu with .focus() ?
Code :
<div class="navbar navbar-default navbar-static-top" role="navigation">
<div class="container">
<ul class="nav navbar-nav">
<li class="dropdown"> Dropdown<span class="caret"></span>
<ul class="dropdown-menu" role="menu" style="min-width: 250px;">
<li>
<div style="padding:4px 20px;">Link:</div>
</li>
<li>
<div style="padding:4px 20px;">
<input class="form-control" id="ha" type="text" placeholder="blabla" />
</div>
</li>
</ul>
</li>
</ul>
</div>
</div>
JS :
{
var maa = document.getElementById('maa');
console.log(maa);
maa.addEventListener('click', function () {
console.log($('#ha'));
$('#ha').val('Bonjour');
$('#ha').focus();
});
};
jsFiddle Demo
The element exists at the time of the click, so changing its value and logging it will properly show the current state of the element. However, it has not been displayed yet and as a result focusing it will not really have any effect. You could probably refactor some small snippet in the library to expose a hook that you could use to make your focus work. Or, you could make the observation that in the very next event handler the element will be visible and use a small timeout.
maa.addEventListener('click', function () {
console.log($('#ha'));
$('#ha').val('Bonjour');
setTimeout(function(){$('#ha').focus();},10);//timeout here
});
the simplest solution i came in mind is to just delay the focus. the reason its not focusing is because the element is not yet visible.
http://jsfiddle.net/xab7Leoq/
setTimeout(function() {
$('#ha').focus();
}, 100);
another solution is to find out when its getting visible, and then do it. it may be a better solution yet more complicated. :)
edit1: stopping propagation:
// Prevents the propagation
$('#ha').click(function(ev) {
ev.stopPropagation();
});
like in http://jsfiddle.net/xab7Leoq/
Figured I might as well post an answer, even if late... since this seems to work well and doesn't require setTimeout: http://jsfiddle.net/cvLbfttL/
$("#maa").focus(function () {
$('#ha').val('Bonjour');
$('#ha').focus();
return false;
});
$('#ha').click(function(){return false;});
The anchor "maa" gets the focus when clicked, and it happens after the click callback/event returns. So you can do your code in the focus event instead. I couldn't figure out how to tab to the anchor inside JSFiddle, but I assume the code would also run if you set the focus to the anchor using some other method, but that should be fine I think, maybe even nice.
An example using callback function. Man avoid to use setTimeout() function, because the results are unpredictable.
http://jsfiddle.net/v62tdn9z/
var $maa=$('#maa'), $ha=$('#ha');
$maa.mousedown( function () {
$ha.val('Bonjour');
$maa.mousemove(function () { $ha.focus(); });
});
Having a tabindex on the element could be the solution. This worked in my case.

Toggle does not work on the same element that show works on

I am trying to use JQuery toggle, so when a user clicks the info icon, the hidden div containing item information is shown / hidden. For some reason it is not working for me.
While trying to debug, I noticed that show(), correctly shows the target element that I would like to toggle. However, when I replace show() with toggle(), it does not work and does not return any error.
I was wondering if someone can help me identify the cause of this problem.
My Markup
<div class="option">
<div class="prod-text">Toy Whistle </div>
<div>
<img class="info-icon" src="Info-icon.png">
</div>
<div class="option-info" style="display:none;">
<div>
<div class="price-text">Price: $100</div>
<div class="prod-id-text">Item Number: 231912</div>
<div class="quantity-text">Quantity: 72</div>
</div>
</div>
</div>
JQuery (does not work)
$(".info-icon").click(function(){
$(this).parent().parent().find('.option-info').toggle();
});
JQuery (works!)
$(".info-icon").click(function(){
$(this).parent().parent().find('.option-info').show();
});
Many thanks in advance!
Perhaps the click event handler is getting bound twice, and thus fire twice for each click. The show() would work fine in this case, but the toggle() would show and then immediately hide the element each time you click. Try this:
$(".info-icon").click(function(){
console.log('click handler fired');
$(this).parent().parent().find('.option-info').toggle();
});
And run this with Web Inspector or Firebug enabled to see how many messages are logged for each click.

Categories