JS mouseenter triggered twice - javascript

The problem is about event mouseenter which is triggered twice.
The code is here : http://jsfiddle.net/xyrhacom/
HTML :
<div id="elt1" class="elt" val="text1">
text1
<div id="elt2" class="elt" val="text2">
text2
<div>
</div>
JS :
$(document).ready(function() {
$(".elt").mouseenter(function() {
console.log($(this).attr('val'));
});
})
I understand the problem is the event is linked to the class attribute so it is triggered for each class, but I need to find a way to consider just the event triggered for the child.
In the example, when mouseover text2, it displays in the console 'text2 text1' but I want to find a way to only display 'text2' (keeping the same HTML code)

use stopPropagation(); Prevents the event from bubbling up the DOM tree,
$(document).ready(function() {
$(".elt").mouseenter(function(e) {
e.stopPropagation();
console.log($(this).attr('val'));
});
})
Updated demo

Both #elt1 and #elt2 have your selector class (.elt )
use event.stopPropagation() to stop event from bubbling up in the DOM tree
$(document).ready(function() {
$(".elt").mouseenter(function(event) {
event.stopPropagation();
console.log($(this).attr('val'));
});
})

If you only want to let the first child trigger the event, you can use a selector like:
$(".elt > .elt")

The issue here is that elt2 is inside elt1, and the mouseenter event is bubbling up the DOM chain. You need to stop the bubbling by using event.stopPropagation() to prevent your function from firing multiple times:
$(document).ready(function() {
$(".elt").mouseenter(function(e) {
e.stopPropagation();
console.log($(this).attr('val'));
});
})
I've made a fiddle here: http://jsfiddle.net/autoboxer/9e243sgL/
Cheers,
autoboxer

Related

How to convert jQuery to JavaScript name attribute

I'm trying to find a way to create 'on click' events for dynamically generated buttons in JS. I know that in jQuery it can be done like this:
$(document).on('click', 'name=[buttonName]', function() {});
I know the e.target method in JS, but I'm wanting to find a way to do it with a name attribute instead.
Thanks
Firstly that line of jQuery isn't quite right as the square brackets are in the wrong place:
$(document).on('click', '[name="buttonName"]', func);
To achieve the same in plain JS you would need to attach a click event handler to a static parent element, then check the name property of the clicked element:
document.addEventListener('click', function(e) {
if (e.target.name == 'buttonName') {
// do something...
}
});
document.addEventListener('click', function(e) {
if (e.target.name == 'buttonName') {
alert('Hello!');
}
});
<button>I do nothing!</button>
<button name="buttonName">I say hello!</button>
You can use querySelector in a similar way than you would in jQuery, and attach the event listener whenever a new element is added to the DOM.
document.querySelector("button[name='buttonName']").addEventListener("click", function(){
alert("Hello, World");
});
<button name="buttonName">Click me</button>
The difference to the original jQuery code is that in that example it listens to events on the document whereas this does not.
You can use getElementByName to add click event to your button which is dynamically render
document.getElementByName("ButtonName").addEventListener("click", function(e) {
});

Jquery one() function fires twice on click

My Jquery one() function dies after second click instead of first click. Here is my HTML
<div class="box">
<div class="call" data-tai="5">CLICK</div>
</div>
and heres my Jquery
$('body div').one('click', '.call', function() {
var mother = $(this).parent();
if(mother.css('position') === 'static')
mother.css('position', 'relative');
var tai = $(this).data('tai');
$.ajax({
method: 'GET',
url: '/bootstrap/call.php',
data: 'tai='+tai,
dataType: 'html',
success: function(ret) {
mother.append(ret);
},
});
return false;
});
Interesting thing is, if i don't use return false;, it dies after first click. However bubbling occurs and it appends 2 html tags instead of 1, inside box element. Thanks for help
$('body div')
would select both the divs and attach click handlers to both of them. When you click on the nested div then, both clicks will be fired. Use a specific selector to avoid this.
$('.call')
could perhaps achieve this.
That's because event handlers bound by using .one will be fired once for each element in the jQuery collection. Since the return false stops the propagation of the event, if you click on the .call element, click handler of the parent element is not executed but the parent element still has an active click handler. You should use a more specific selector for selecting the target element. If the click handler should be bound to the div.call elements:
$('.box div.call').one(...);
Now, if .box elements have 9 div.call descendants then you have 9 click handlers! After clicking on each element jQuery unbinds the handler for that specific element.
It's not once for all elements, it's once for each element.
If the handler should be called once for all the matching elements you can use the delegation version of the .one method:
$(document).one('click', '.box div.call', function() {
// ...
});
And if you want to delegate the event and have the handler working once for dynamically generated elements you can use the .on method and :not selector:
$(document).on('click', '.box .call:not(.clicked)', function() {
$(this).addClass('clicked');
// ...
});
Now the handler is called once for each .call element. Since :not excludes the elements that have .clicked class the selector doesn't match the already-clicked elements.
Events bubble in JavaScript. Your code
$('body div').one('click', '.call', function() {
}
wires up on both
<div class="box"> <!-- This -->
<div class="call" data-tai="5">CLICK</div> <!-- And this -->
</div>
You need a more specific selector. If this div is a parent element in the body like this:
<body>
<div class="box">
<div class="call" data-tai="5">CLICK</div>
</div>
<div class="box">
<div class="call" data-tai="5">CLICK</div>
</div>
</body>
then you can use a selector like this:
$('body > div').one('click', '.call', function() {
}
The question is - where do you expect your click event to be placed? Perhaps the div with the box class?
$('div.box').one('click', '.call', function() {
}
This assumes that the .call divs are being added dynamically to the .box div.
P.S. - if you want to stop the bubbling, I suggest you pass in the event object to your click event and call stopPropagation()
$('div.box').one('click', '.call', function(evt) {
evt.stopPropagation(); // no bubbling
}

How do I select a class but not its inside element?

Say I have
<div id="mydiv">
<div class="myclass">
<span class="otherclass"></span>
and many other classes...
</div>
</div>
I want to capture the click event on .mydiv but not inside .myclass.
I tried .mydiv:not(.myclass) but it doesn't seem to work. I think it's because I might be clicking on the otherclass so the :not(.myclass) is not working. How can I get the area I want to get? Thanks!
make #mydiv clickable, do whatever you wish, and stop event propagation from .myclass, so the event will not bubbleup from myclass to mydiv
$('#mydiv').click(function(){
// do anything
})
// stop event propagation
$('.myclass').click(function(e){
e.stopPropagation();
})
You can click on mydiv id and write your code in that function and on .myclass click event you simply write return false to stop further execution of function.
$('#mydiv').click(function(){
// stuff your code here
});
//Use `return false` instead of `e.stopPropagation();`
$('.myclass').click(function(e){
return false;
})
e.stopPropagation() is dangerous please read Documentation
Calling .off() will remove an event handler
$("#mydiv").on('click', function () {
alert("You clicked mydiv");
});
$(".myclass").off('click', function () {
});
or like this
$(".myclass").off();
JS FIDDLE

Using "on" for response for desired elements only:

JS Fiddle Link
I am dynamically adding some elements and my div looks like:
<div class="knock" href="#">
<!-- Do Something if links are not clicked -->
Google
Facebook
</div>
And my on script is:
$(".knock").on("click", function(){
console.log("Link not clicked");
alert("Link not Clicked");
});
My Problem, I do not want to fire the alert when the links are clicked. Is there a way out?
You can write anchor tag event and stop event Propagation of the event to upper DOM elements so that alert only comes up when the div is actually clicked, but not when some anchor tag inside div is clicked:
$(".knock").on('click',"a",function(event){
event.stopPropagation();
})
FIDDLE:
http://jsfiddle.net/hbac7vbh/2/
event.stopPropagation:
The event.stopPropagation() method stops the bubbling of an event to parent elements, preventing any parent event handlers from being executed.
See details here on jquery official page
Just determine if the a is clicked based on the event that is passed.
Updated Example
$(".knock").on("click", function(e){
if(!$(e.target).is('a')){
console.log("Link not clicked");
alert("Link not Clicked");
}
});
Add this to your js:
$(".knock a").on("click", function(e) {
return false;
});
Why not add another method as
$('a').on('click',function(e){
e.stopPropagation();
});
This will stop porpagation of the chaininvocation of events on parent elements.
See updated Fiddle

jquerys' e.stopPropagation() cannot get required functionality

photoContainer below has children. This works okay, but if I click on any of its children the code execute, hides blackLayer and removes photoContainer. How can I prevent this from happening and yet execute when I click anywhere but on photoContainer children ?
Thanks.
$('div#photoContainer').live('click', function (e) {
e.stopPropagation();
var blackLayer = $('div#blackLayer');
if (blackLayer.length) {
blackLayer.fadeOut();
}
$(this).remove();
});
I believe the problem is that you are stopping the propagation of the event on the parent element, you want to stop the propagation of the event on the children of the #photoContainer element so it does not propagate up to the #phoeoContainer element:
$('#photoContainer').live('click', function (e) {
var blackLayer = $('div#blackLayer');
if (blackLayer.length) {
blackLayer.fadeOut();
}
$(this).remove();
});
$('#photoContainer > div').live('click', function (event) {
event.stopPropagation();
});
This will stop the propagation of the click event when it is triggered on a child div of the #photoContainer element.
Here is a demo: http://jsfiddle.net/J9dBS/2/ (notice that if you click on the "child" element that no alert is shown)
I would like to note that .live() is deprecidated as of jQuery 1.7. If you are using jQuery 1.7 or later then it's suggested to use .on() like this:
$(<root-element>).on(<event>, <selector>, <event-handler>)
Or if you are using jQuery 1.4.2 to jQuery 1.6.4 then it's suggested that you use .delegate():
$(<root-element>).delegate(<selector>, <event>, <event-handler>);

Categories

Resources