Jquery one() function fires twice on click - javascript

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
}

Related

How to trigger click on dynamically created element

I know we can bind event to dynamically created elements like below
$('some').on('click','class/id of dynamic ele',function(){});
but how to trigger click event on dynamically created element like i have created new element in dom
<div class="one">M</div>
now how can i $( ".one" ).trigger( "click" ); ?
$(document).on('click', '.one', function() {
use this one to put click on dynamically created element
find the DOCUMENTATION for more info
but how to trigger click event on dynamically created element like i
have created new element in dom
Try defining <div class="one">M</div> without attributes <div">M</div>; setting attributes at second argument to jQuery( html, attributes ) , utilizing .click()
jQuery( html, attributes )
html
Type: htmlString A string defining a
single, standalone, HTML element (e.g. or ).
attributes
Type: PlainObject An object of attributes, events, and
methods to call on the newly-created element.
Important: If the second argument is passed, the HTML string in the first argument must represent a simple element with no attributes.
As of jQuery 1.4, any event type can be passed in, and the following jQuery methods can be called: val, css, html, text, data,
width, height, or offset.
// create dynamic element
$( "<div></div>", {
"class": "one",
"text": "abc",
"on": {
// attach `click` event to dynamically created element
"click": function( event ) {
// Do something
console.log(event.target, this.textContent)
}
}
}).appendTo( "body" )
// trigger `click` event on dynamically created element
.click()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
Yup. .trigger() should do:
Snippet:
var myDIV = $('<div id="myDIV"> </div>');
$(document.body).append(myDIV);
$(document).on('click', '#myDIV', onClick);
function onClick() {
alert('hello');
}
myDIV.trigger('click');
div {
background-color: #cc0;
width: 100px;
height: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
But then again, if this is something you want to do when the document is ready or when the window has loaded, then you probably don't need to .trigger(), you can call the function directly.
Store that element in a variable, use the same to append dynamically in the body and then trigger click on it:
var div = "<div class='one'>M</div>";
$("body").append($(div));
//Your code//
$(div).trigger("click");
Or if there are multiple elements with same class and this is the last element then:
$(".one:last").trigger("click");
Did you ever try with delegate? if not you try like this for your dynamically added content.
$('body').delegate("div.one", "click", function(e){
// do you other works here
});
check this here
Hope your problem is solved. :)
As no FIDDLE provided, I have assumed the following markup
<a class="some">Click To Add</a>
<br/>
<div class="container">
</div>
css class
.one
{
background-color: Grey;
}
.some
{
background-color: Red;
}
Assigning click event after the control added to the DIV(with container class)
$(document).ready(function(){
$('.some').click(function(){
$('.container').append("<div class='one'>M</div><br/>");
$('.container div').off('click').on('click',function(){
alert("Clicked");
});
});
});
Try The FIDDLE, and share your inputs if any.
Hope this helps ............
i am posting this answer as in all the answers i can't see where to put this trigger method.
If you have any implementations like .append(), .html() of jquery or .innerHTML, .appendChild() of plain js then after execution of it, or i would say whenever you append your element in the DOM, right after it you can use any event to be triggered but some event has to be bound on it.
So, element has to be in the DOM to fire/trigger any event.
Take this example:
var div = $('<div id="aaa">aaa</div>');
$(document.body).append(div).on('click', '#aaa', divClik);
function divClik(e) {
alert(this.id+' clicked.');
}
div.trigger('click');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

jquery .on() doesn't work for cloned element

It seems .on() failed to bind newly created element from clone()
<div class="container">
<div class="add">add</div>
</div>
$(".remove").on("click",function() {
$(this).remove();
});
$(".add").on("click", function() {
$(this).clone().toggleClass("add remove").text("remove").appendTo($(".container"));
});
jsfiddle
Why this doesn't work?
Update:
please note that, I know .clone() takes two parameters, but I don't want to let the cloned element continue registered to the old events, but a new one, I could use .off() and .on() to register again, but my question is why the previously declared .on(".remvove") didn't capture the change in the cloned element.
Because you need to pass a boolean parameter to clone so that all data and event handlers will be attached to cloned element.
https://api.jquery.com/clone/
$(".remove").on("click",function() {
$(this).remove();
});
$(".add").on("click", function() {
$(this).clone(true).toggleClass("add remove").text("remove").appendTo($(".container"));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="container">
<div class="add">add</div>
</div>
Edited
$(".container").on("click", '.remove', function() {
$(this).remove();
});
$(".add").on("click", function() {
$(this).clone().toggleClass("add remove").text("remove").appendTo($(".container"));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="container">
<div class="add">add</div>
</div>
"my question is why the previously declared .on(".remvove") didn't capture the change in the cloned element."
Because the event listener was attached to all the elements with class names .remove which existed in the DOM at that point in time.
But with clone you created a new Element. It has just been created. A fresh node. How can your earlier listener work on this.
Solutions:
1.) Either use event delegation and attach your listener to a static ancestor node
2.) Pass the boolean flag while calling the clone function so that your listeners also get copied.
3.) Register the Event Listener Again on that node.
Unbind and bind the function.
bindEvent();
function bindEvent(){
$(".remove").unbind("click");
$(".remove").bind("click",function() {
$(this).remove();
bindEvent();
});
$(".add").unbind("click");
$(".add").bind("click", function() {
$(this).clone().toggleClass("add remove").text("remove").appendTo($("body"));
bindEvent();
});
}
jsfiddle

Is it impossible to create a function for a created element through coding?

var div = document.createElement('div');
div.setAttribute('class', 'asd');
parent.appendChild(div);
This code basically creates a div and appends it inside the parent element.
$(".asd").hover(function(){
alert("hey");};
This one is a function when hovering the created div. But it doesn't work. Any solution?
You forgot a closing parenthesis:
$(".asd").hover(function(){
alert("hey");
});
But really, if you're adding the element dynamically, you should change your hover event to one that uses mouseover and mouseout, and use event delegation so that your event can be caught as it bubbles up the event ladder (or whatever it's called):
$(document).on('mouseover', '.asd', function () {
console.log('on')
}).on('mouseout', '.asd', function () {
console.log('off')
});
And you if you're going to use jQuery I'd suggest that you use it for all your DOM manipulation. Using document.createElement and jQuery is kinda strange.
DEMO
Sure, but you'll need to use event delegation:
$(document).on('mouseenter', '.asd', function() {
// do stuff here
}).on('mouseleave', '.asd', function() {
// undo stuff here
});
This applies the event listener to some ancestor element that exists on DOM load, and only runs the function if the event target is the element listed as the second argument.
This method allows you to add elements to the page at will without having to create new hover listeners. Any element with class asd will have the listeners attached.
If performance is a concern, substitute any ancestor element that's available on DOM load for document to reduce the scope of the listener.
http://api.jquery.com/on
Please enclose all the code in DOM ready or put the code at the bottom of the page:
Note: For this demo, I added function() {} as the second parameter of hover so that the alert does not appear twice ... I could/should have used focusin event.
$(function() {
var parent = $('.parent')[0];
var div = document.createElement('div');
div.setAttribute('class', 'asd');
parent.appendChild(div);
$(div).hover(function() {
alert("hey");
}, function() {});
});
.asd {
border: 1px solid #000;
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent"></div>
event delegation is wrong on dynamically created div and there is a parentheses mistake
write it like this
$(document).on(hover,"asd"function(){
alert("hey");
});
Plus you can leave creating div to jquery
parent.appendChild('<div class="asd"></div>');

How to select all the elements in the DOM except one element?

I have an jQuery events) that are triggering on every DOM element on the page.
That's fine for now, but I need a way to exclude a div (with child divs as well) from DOM selection in order to prevent triggering event on them.
I've tried jQuery's unbind(), not() and off() directly on $('#myDiv'), but the events are still triggering.
The code that triggers the event(s):
$("*").each(function () {
// here are events bound to every DOM in the page
$(this).mouseover(mouseover).mouseout(mouseout).click(click);
});
I've also tried with
$("*:not(#myDiv)").each(function () {
// events
$(this).mouseover(mouseover).mouseout(mouseout).click(click);
});
and still wasn't able to remove events from #myDiv.
The HTML:
<div id="myDiv">
<div class="data">
<!-- -->
</div>
<div class="debug">
<!-- -->
</div>
<div class="form">
<!-- -->
</div>
</div>
What is the best way to make full DOM selection but excluding #myDiv, so I would be able to use bind() or on() for binding events?
NOTE: I don't want to remove #myDiv from the DOM tree, but rather exclude it from selection.
You may try this
$(function(){
$('body > *').not('#myDiv')
.on('mouseover', function(){ //... })
.on('click', function(){ //... });
});
An Example.
Try .not()
$("*").not("#myDiv").each(function () {
$(this).mouseover(mouseover).mouseout(mouseout).click(click);
});
Try the following:
$("*:not(#myDiv):not(#myDiv *)")
.mouseover(mouseover)
.mouseout(mouseout)
.click(click)
This will exclude not only #myDiv, but any child elements of #myDiv (which you seem to be going for).
If you want to exclude the children as well, you'll need to do so explicitly:
$("*:not(#myDiv):not(#myDiv *)")

How to trigger a class-targeted method AFTER the class has been added to an element?

In the below markup, the #enable button will add a class to the #show div. This class has a method attached to it that fades in/out the #hidden span.
However, even though the class is added to the #show div, the method attached to the class isn't triggered.
HTML
<input type='button' id='enable' value='Enable' />
<div id='show'>
Testing.. <span id='hidden'>Testing, 1, 2, 3.</span>
</div>​
JS
$(function() {
// Adds .testing class after the button is clicked. however..
$('#enable').click(function() {
$('#show').addClass('testing')
});
// It will not trigger after .testing class has been added to DIV?
$('.testing').hover(function() {
$('#hidden').fadeIn();
}, function() {
$('#hidden').fadeOut();
});
});​
Fiddle to work with: http://jsfiddle.net/jS3nM/
It seems I am missing something conceptually. What is the correct way to handle this?
jQuery does not work like CSS. When you do, $("selector"), it will return a list of elements in the document that match that selector right now.
You will then operate on those elements with jQuery methods. There is no magic like "class-targeted method" going on.
You can find add a event listener to document:
$(document).on({
mouseenter: function() {
$('#hidden').fadeIn();
},
mouseleave: function() {
$('#hidden').fadeOut();
}
}, ".testing");
document is always found and always exists, and the event listener is added to that. The selector at the end filters out what elements are qualified for the event.
Because when you bind the hover handler there is no element with class of testing in the document, you should delegate the event, you can use the on method, try the following"
$(document).on('mouseenter', '.testing', function(e) {
$('#hidden').fadeIn();
});
$(document).on('mouseleave', '.testing', function(e) {
$('#hidden').fadeOut();
});

Categories

Resources