I have a hyperlink with an ID when clicked will perform a certain event using JQuery. JQuery records the existence of this link on document load. Some time during the course of the users visit. I remove that link and the re-add it later. However, that even is not fired off again when that link is clicked after it has been removed and added.
Why is the case and how can I remedy it? Something to do with event binding?? Or shall I just add an onclick attribute?
You've been using a tag like this to add the click event:
$('#speciallink').click(function(){
// do something
return false;
});
This will bind the event to the elements that are selected at that moment.
Removing a link and adding it again, will effectively create a new element, without this event. You can use the "live" method to add rules that will be applied to events matching the rule, even when these elements are created after creating the rule:
$('#speciallink').live("click",function(){
// do something
return false;
});
You will need to bind that event handler to the new element when it is added or you could use live() instead of bind to achieve what you need.
Basically, the event handler references the original element. When that element is removed, even though a new element is added with the same id, it is a different element.
Don't remove the link from the DOM tree. Instead, just toggle its visibility with show() and hide().
Removing the element from the DOM tree with remove() will remove the element and all of its event handlers, even if you add it back with the same id.
If you completely remove the element, you will need to reattach any event listeners to the element when you recreate it.
Alternatively, just hide the element by setting its style to display:none with .show() and .hide()
Related
I have a cascading menu with the following flow;
click on an item from menu-1
creates and updates menu-2 li elements
click on an item from menu-2
creates and updates menu-3 li elements
etc..
```
$firstMenu = $('.prime-menu');
$secondtMenu = $('.second-menu');
$thirdMenu = $('.third-menu');
```
As i'm traversing through different elems. within each menu, using find() comes as a blessing, the issue is that the script loads when no menu other than the first menu is created so $secondtMenu.find('.item-year').click(function (clickEvent) {}) is 0 length.
What are my options in JQuery to make my find() functions work on elements that are not loaded yet in the DOM?
I thought of creating an event listener, but I think there are more terse approaches than that.
You should use delegates when dealing with dynamic HTML. For instance, use an outer element like document or body to "start" your finds.
$(document).find(".prime-menu");
EDIT: Find and event delegation
The solution was to use find with event delegation. Example event.
$(document).find(".prime-menu").on('mouseenter', '.track-table tbody tr', function(){ });
You state that when you click on an item from menu-1 it creates and updates menu-2 li elements. In this function is where you should do your event binding. The DOMElement will exist in js before being added to the dom, and that is where your bindings should be set.
If you need help share this code with us I'm sure myself or someone will be able to help you sort it out.
Bind the click handler to the menu parent, not the actual menu items.
Something like this might work...
$("#menuparent").on("click",".item-year",function(event) {
var clicked_element = event.currentTarget;
});
Doing it this way, even if the element with class .item-year is added to the dom after the click event is bound, it will still register the click.
Let's say I have an element:
<section id="container">
<div id="curious">hey, there</div>
</section>
Then, after the DOM loads, I bind an event to the element, like so:
$('#curious').click(function (){
alert('Are you curious?');
});
Later on, the element gets deleted:
$('#container').html('');
What happens to the bound event? Is it deleted too? Does it linger around? Is it a good practice to clean it up?
According to the jQuery documentation for the .html() method, the event handlers are removed.
This is done to prevent memory leaks.
When .html() is used to set an element's content, any content that was in that element is completely replaced by the new content. Additionally, jQuery removes other constructs such as data and event handlers from child elements before replacing those elements with the new content.
Similarly, the same applies when using the .empty()/.remove() methods as well:
all bound events and jQuery data associated with the elements are removed.
If you want to retain the data and event listeners, use the .detach() method instead. The .detach() method is essentially the same as the .remove() method except for the fact that it keeps all jQuery data associated with the removed elements (which means that you can append the same element after detaching it, and the events would still be bound).
Ok I create element, assign click handler, and append it to body. Then i remove it and reappend it and click handler is no longer working???
Why would this happen.
var btn = $('<button>').text('hi').click(function(){console.log(3);});
var div = $('<div>');
div.append(btn);
$('body').append(div);
//click it now, it works..
div.html('');
div.append(btn);
// now button doesn't work..
So why is this happening and what can i do to fix it.
Since .html('') is essentially the same as .empty(), the following applies (from the jQuery docs):
To avoid memory leaks, jQuery removes other constructs such as data and event handlers from the child elements before removing the elements themselves.
If you want to remove elements without destroying their data or event handlers (so they can be re-added later), use .detach() instead.
One option would be to use event delegation. In doing so, the event isn't bound directly to the button element, it is bound to a constant parent element that isn't removed.
Example Here
$(document).on('click', 'button', function () {
// ..
});
As mentioned above, another option would be to use the .detach() method in order to remove the element from the DOM, without removing attached event listeners.
The .detach() method is the same as .remove(), except that .detach() keeps all jQuery data associated with the removed elements. This method is useful when removed elements are to be reinserted into the DOM at a later time.
Example Here
div.find('button').detach();
div.append(btn);
put this after the second div.append(btn); - > btn = $('button').text('hi').click(function(){console.log(3);});
This is very interesting situation. What happens when you clear div with html('') method. Take a look at source code and you will see that internally jQuery calls jQuery.cleanData(getAll(elem, false));. This method is responsible for removing all the related data for all child elements that have already been removed. This is important in order to avoid memory leaks.
Clearing data also removes events bound with on (and similar) methods, because those event handlers are also stored in internal cache object.
So as the result, even though you removed content of the div, the btn object is still in memory, but the event bound to it previously is gone.
This was the explanation of the problem. The solution is to use dedicated method called detach. It will remove button from the DOM but will keep event data in case element will later be appended again.
// remove element but keep its data
btn.detach();
// append back
div.append(btn);
In situations like this you should not use html('').
It happens because you're calling html() on the DIV that contains the button.
When you call html() with an empty string, it calls empty() internally.
Calling empty() on an element iterates over all the elements inside that element removing all data and events securely.
It does this by calling jQuery.cleanData on the button, which again explicitly calls jQuery.removeEvent, removing all events on the button.
The button is still stored in the variable btn, so it can be appended again, but it has lost all data and any events attached to it because the parent element had html("") called on it.
The solution is to use detach() to remove the element with all the data and events intact, so it can be appended again, or you can attach the event to a parent element that isn't removed, or you could just hide the element, generally there's no reason to remove the element just to reappend it, it's better to hide it.
FIDDLE
I am creating a clone of a div, but unfortunately i am not able to add event listener to cloned div.
I tried using clone(true,true) but still did not get it running.
Can some one help me out with it please
JS fiddle for clone
Clicking image next to And, adds a new div
Code i tried for adding event listener
$("#add").on('click',function () {
$("#cont").clone(true, true).appendTo(".container");
});
First you should change your cont id to a class as multiple ids are bad and won't work properly.
Second, use jQuery's first method to grab the first in the returned jQuery nodelist that you get from grabbing all the cont classes: $('.cont') and then clone the node. You have to grab only the first one or you'll end up adding multiples of the div back on to the page.
$(".cont").first().clone(true, true).appendTo(".container");
Third, change the delete id to a class.
Fourth, because you're adding to the DOM you need to use event delegation on the parent node in order to catch the events properly. Use closest to find the nearest cont class and remove it.
$('.container').on('click', '.delete', function () {
$(this).closest('.cont').hide();
});
Fiddle
Hope this helps.
As most of us know, once an element has been loaded it is possible to attach an event to it by simply using the normal JQuery events.
The question is, what if I want to create a specific event, and define that an element with a specific class or id, will get that event automatically when they are loaded?
For example:
I have a function that checks whether the input that has been entered is numeric only, and allows only numbers to be entered inside an input.
To do that I add the class "numeric" to the input element.
Normally I would just run a script right after with JQuery or just by using the onkeypressed DOM event to attach that function to it.
However, let's assume I have an ajax request that attaches a new from page, with the class numeric in the proper input elements.
Using the script again using the same class selector will result in the event run 2 times for elements that were loaded earlier.. And for every time I run that script it will add that event over and over...
What I do now, is I used the "unbind" first, and then reattach the event to all elements, and it is working perfectly! But I am looking for more elegant solution.
Any suggestions?
You need to use the .on with event delegation
Syntax
$(parent-selector).on(event,target-selector,callback);
Note: The parent-selector must be parent element which is present in the DOM while binding the event, generally people use document and body, but for the performance you must have the nearest parent possible to the target
Example
$(document).on("click",".button",function(){
alert("Button Clicked");
});
Use the on function to attach event handlers for elements that do not exist.
$(document).on("keypress", ".numeric", function(){
//do something
});
JS Fiddle: http://jsfiddle.net/T34Ph/