The below code is not binding the event to an appended element (using .insertBefore()).
From my understanding, .on() is supposed to work like .live(). Is this not the case?
<div class="todoColumn">
<div class="projectHeader">
<div class="title">Example</div>Subtitle
</div>
<div class="todo">
<div class="checkbox"><span class="check pictos">3</span></div>
<div class="text">another test</div>
<div class="floatfix"></div>
</div>
<div class="todo">
<div class="checkbox"><span class="check pictos">3</span></div>
<div class="text">another test</div>
<div class="floatfix"></div>
</div>
</div>
$('.todoColumn .todo .checkbox').on('mouseenter', function() {
$(this).find('.check').css('visibility','visible');
});
It depends upon where you put the selector. Putting it in the first jQuery object does not have any .live() behavior. It binds static event handlers.
Specifying a comment parent object in the jQuery object and putting the selector in the arguments to .on() gives you live behavior:
$(document.body).on('mouseenter', '.todoColumn .todo .checkbox', function() {
$(this).find('.check').css('visibility','visible');
});
It will work even more efficiently (and better than .live()) if you pick a common parent that is closer to the actual objects than document.body. A problem with .live() was too many event handlers (all with selectors to check) on the document object. .on() works more like .delegate() and allows you to put the event handler on a common parent that is closer to the actual objects.
EDIT: Now that you've included your HTML, more efficient code would be this with a common parent selector in the jQuery object and the simplest possible selector in the .on() arguments:
$('.todoColumn').on('mouseenter', '.checkbox', function() {
$(this).find('.check').css('visibility','visible');
});
To use it the way you want, you need to place the selector in the function and bind the event to the document:
$(document).on("mouseenter", ".column .todo .checkbox", function(){
// do stuff
});
And, like jfriend00 suggested, it's more efficient to bind the event to the closest parent:
$(".column .todo").on("mouseenter", ".checkbox", function(){
// do stuff
});
Related
I have some elements that I add to the DOM after the page has been loaded. And I'd like to perform some actions when I click on them. I'm using the delegation with jQuery but I don't know how to get the clicked element when I'm in the fonction ($(this) refers in this case to the parent)
<div id="parent">
<div class="child">
<div class="hidden"></div>
</div>
<div class="child">
<div class="hidden"></div>
</div>
</div>
<script>
$('#parent').click('.child', function(){
$(this).find('.child').toggleClass("hidden displayed")
});
</script>
Let's say I want to toggle the inner div from "hidden" to "displayed" when I click on the "child" div. Currently when I click on the first "child" div, the two "hidden" div will be toggled, and I want to be toggled only the one in the div I clicked.
Use e.target to find out which element the event originated on.
$('#parent').on('click', '.child', function(e){
$(e.target).toggleClass("hidden displayed")
});
I also fixed the code a bit - you need to use .on for delegated events. (Mentioned by Barmar.)
You need to use .on() to delegate events. As the documentation says:
When jQuery calls a handler, the this keyword is a reference to the element where the event is being delivered; for directly bound events this is the element where the event was attached and for delegated events this is an element matching selector.
So it should be:
$('#parent').on('click', '.child', function() {
$(this).toggleClass("hidden displayed");
};
Your use of .click('.child', function...) does not do delegation. It matches the function signature:
.click(eventData, handler)
described here. So it's just binding to the parent, not delegating to the child, that's why you get the wrong value in this.
I am simply trying to create a function that allows me to add a div with content using jQuery .prepend() and then when that div is clicked it is removed using .remove().
Prepend seems to work fine, but I am having trouble getting the .remove() to work on prepended divs. It works fine on divs that were already present.
Could anyone possibly help me with where I am going wrong?
Here is my code:
<script language="javascript" type="text/javascript">
$(document).ready(function(){
$(".DivAdd").click(function(){
var thisDivItem = $(this).attr('add');thisDivItemid = "DivItem"+$(this).attr('add');
$( ".DivItem" ).parent().prepend( "<div id='"+thisDivItemid+"' class='DivRemove')>"+thisDivItem+"</div> " );
});
$(".DivRemove").click(function(){ $( this ).remove() });
});
</script>
<div class="DivAdd" add="321">Div Add</div>
<div class="DivItems">
<div class="DivItem DivRemove" id="DivItem1">1</div>
<div class="DivItem DivRemove" id="DivItem2">2</div>
<div class="DivItem DivRemove" id="DivItem3">3</div>
<div class="DivItem DivRemove" id="DivItem4">4</div>
<div class="DivItem DivRemove" id="DivItem5">5</div>
<div class="DivItem DivRemove" id="DivItem6">6</div>
<div class="DivItem DivRemove" id="DivItem7">7</div>
</div>
Try using:
$(".DivItems").on('click', '.DivRemove', function(){ $( this ).remove() });
As others have mentioned, .on() refers to the concept of event delegation.
You need to delegate your event handlers. This is because the element is dynamically added, and not in the DOM at the time jQuery was initialized. So it's pretty much like jQuery doesn't know about this object. You can delegate the event handler on something that will exist at the time of page load. For example, if your appended div were inside of a wrapping div:
$('.wrapper').on('click',".DivRemove", function() {
//do stuff
});
This is the principle of delegate():
Attach a handler to one or more events for all elements that match the selector, now or in the future, based on a specific set of root
elements.
$('.DivItems').delegate('.DivRemove', 'click', function(){
$( this ).remove() });
});
Or you can use on() for this, which is preferred:
$('.DivItems').on('click', '.DivRemove', function(){
$( this ).remove() });
});
Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time. By
picking an element that is guaranteed to be present at the time the
delegated event handler is attached, you can use delegated events to
avoid the need to frequently attach and remove event handlers.
This will do what you need. This will bind to existing and dynamic elements added to the dom as well.
$(document).on('click','.DivRemove',function(){ $( this ).remove() });
http://jsfiddle.net/q98G6/
HTML
<p>[QUESTION]</p>
<div class="answer-notdone">
<p>[CONTENT_1]</p>
</div
<div class="answer-notdone">
<p>[CONTENT_2]</p>
</div
<div class="answer-notdone">
<p>[CONTENT_3]</p>
</div
JavaScript
$(".answer-notdone").click(function(){
markQuestion(this); //external function
$(".answer-notdone").addClass('answer-complete').removeClass('answer-notdone');
)};
The example above is for a multiple choice question in a quiz - the user should only be able to click the answer once, and then it should be 'unlinked' from that jQuery function.
But the problem is even after the class has been removed successfully, the jQuery function is still called when clicked. Why?
Here is a fiddle I made of a demo, if the code above was not clear: http://jsfiddle.net/q98G6/
The selector is only used to find the elements, once the element is found and the event handler is attached to it, the selector does not have any relevance because the handlers are attached to the element not to the selector.
One way to solve the problem is to make use event delegation. In event delegation the handlers are attached to an ancestor element and we pass a selector as a target element. In this method the target selector is evaluated lazily.
$(document).on('click', ".answer-notdone", function(){
markQuestion(this); //external function
$(".answer-notdone").addClass('answer-complete').removeClass('answer-notdone');
)};
The selector returns all the elements that match it at the time you bind the handler, and then it attaches the handler to all those elements. Changing an element's class later does not remove the event handlers that were already bound.
If you want your handler to be bound to dynamically changing elements, you should use delegation:
$(document).on('click', '.answer-notdone', function() {
...
});
Try this
$(document).on('click',".answer-notdone",function () {
//markQuestion(this);
$(".answer-notdone").addClass('answer-complete').removeClass('answer-notdone');
});
FIDDLE DEMO
This is the element which I want to remove:
<div id="tobeRemoved">
<div class="eventAttached"></div>
<div>
<div class="eventAttached"></div>
</div>
</div>
And its child may be have event attached.
And now I want to remove it from the DOM tree; I know I can use this:
var ele=document.getElementById("tobeRemoved");
ele.parentNode.removeChild(ele);
But how about the events? Are they cleared at the same time auto?
BTW, I prefer to a cross-browser solution.
You could try this if you know the event type:
function removeEventHandler(elem,eventType,handler) {
if (elem.removeEventListener)
elem.removeEventListener (eventType,handler,false);
if (elem.detachEvent)
elem.detachEvent ('on'+eventType,handler);
}
or jQuery's .unbind() function.
If the events are added with jQuery it will remove the events when the elements are removed.
Suppose I have the following HTML:
<div class="container">
<span class="remove">remove</span>
</div>
and jquery:
$(".container").delegate(".remove", "click", function() {
alert('yes');
});
This works, but now I have HTML like:
<div class"container">
<div>
<span class="remove">remove</span>
</div>
</div>
or even
<div class"container">
<div>
<div>
<span class="remove">remove</span>
</div>
</div>
</div>
So how can I make the jquery work in this case, so that if finds the .remove element in a hierarchy of elements and make the click event work?
NOTE: I'm adding the elements dynamically (using clone function)!
This will still work. As long as the element you're delegating the event to is an ancestor of the element, the element will receive the event.
An exception to this is where an element which is a more direct ancestor stops the propagation of the event using event.stopPropagation(), event.stopImmediatePropagation(), or by returning false in it's handler;
$(".container").delegate(".remove", "click", function() {
// This will never get executed, as the first handler cancels the propagation.
alert('yes');
});
$(".container > div").delegate(".remove", "click", function(e) {
// This handler get the event first as it is closer to the source of the event.
e.stopPropagation();
});
FYI, if you're using jQuery > 1.7, you should consider using the new on() method as on() was implemented to disperse the confusion over live(), delegate() and bind(). It is expected that these older methods will be depreciated in 1.8. The following is equivilent for what you're currently using;
$(".container").on("click", ".remove", function(e) {
alert('yes');
});