Using the Live method to bind a function to dynamically created checkboxes - javascript

How do I bind the following to all future instances of checkboxes that might be added to my page dynamically. I'm not sure how to use the Live() method to do this.
$('input:checkbox').imageTickBox({
tickedImage: "/Content/Img/checkbox_tick.png",
unTickedImage: "/Content/Img/checkbox_notick.png",
imageClass: "tickbox"
});

You cannot do this with .live() (or .delegate()). Those are for binding event handlers for events which may not yet exist.
Description: Attach a handler to the event for all elements which match the current selector, now and in the future.
The image tick box plugin you're using is not any sort of "event." You will have to explicitly call the initialization code (e.g. $('selector').imageTickBox(...)) whenever a new checkbox is added.

.live() is for listening to events and then detecting where those events originated from. Adding elements to the page doesn't trigger anything that .live() can listen to. You'll have to call your plug-in initialization whenever you are adding the checkbox to the page.

This is definitely a duplicate question: Please see
jquery live event for added dom elements
Event binding on dynamically created elements?

Related

jQuery :last-child not updated as additional children are added?

I have a set of inputs where I would like to add another input when the last input currently displayed receives focus. The form starts out with 2 inputs.
$('.answer_fields input:last-child').focus(function(event) {
var nextfield = $('.answer_fields input').length + 1;
$('.answer_fields').append('<input class="form-control answer_field" placeholder="Answer option #' + nextfield +'" id="answer' + nextfield +'">');
});
As it currently stands, additional fields are only appended when the 2nd input (the original "last-child") receives focus.
Checking the source seems to show that the inputs are getting added to the DOM as expected. What am I missing?
The jQuery selector is evaluated ONCE at the time you run the code to install the .focus() event handler. It isn't adjusted live as things change. You can switch to event delegation if you want that type of behavior.
A similar event handler using event delegation that will be evaluated live would look like this:
$(some common parent selector).on("focus", ".answer_fields input:last-child", function() {
// code here
});
Working demo: http://jsfiddle.net/jfriend00/ZZLPJ/
First off, your original code did not work because you were attaching event handlers to specific elements that existed at the time you ran your first code. Which events you had event handlers attached to did not change as your structure changed in the future so new elements would not have event handlers on them and the :last-child portion of your selector would not be re-evaluated.
Event delegation works because certain events that occur on a given element will bubble up the DOM hierarchy through each parent. You can attach a single event handler to a common parent and when that parent is notified that a given event occurred, it can then dynamically evaluate the selector you specified vs. the child item that originated the event and if it's a match, fire your event handler. This gives you the "real-time" selector evaluation that you want in your case.
To give you an idea, these are what I call "static" event handlers:
$(".test:last-child").focus(fn);
$(".test:last-child").on("focus", fn);
This a delegated (and thus dynamic) event handlers:
$("#parent").on("focus", ".test:last-child", fn);
For more info on this topic, see these other answers:
jQuery .live() vs .on() method for adding a click event after loading dynamic html
Does jQuery.on() work for elements that are added after the event handler is created?
Should all jquery events be bound to $(document)?
Just checked to be sure and the focus event does bubble event delegation will work with it.
This is a common question for people starting to use jQuery. It turns out that the named eventListeners (i.e. $.fn.click, $.fn.focus, etc.) attach an event listener to each matching DOM element when the page is first loaded. These listeners are defined on the matching element themselves, meaning that each one is unique to the element it is attached to.
You will hear this method compared to what is commonly known as event delegation. Event delegation involves attaching an even listener to a shared parent element that will check the event.target attribute to see if it matches your criterion (in your case, .answer_fields input:last-child). This differs from attaching a unique listener to each DOM element you wish to target because it allows you to add new nodes to the DOM dynamically, which will then be handled by the parent node's listener like any other node.
To accomplish event delegation using jQuery, use the .on() function on a common ancestor (I'll use document as an example) and listen for all matching elements as the second argument of the function call:
$(document).on('focus', '.answer_fields input:last-child', function(event) {
// your code here
});
Not only will this solve your problem with dynamically created DOM elements, but event delegation will greatly improve the performance of your page by reducing the total number of event listeners attached to elements in the DOM.
For more information about event delegation, I'd encourage you to check out this tutorial and this SO question

Remove all event listeners on a DOM object

Is it possible to remove all event listeners on an object even those declared externally, I have the following code at http://jsfiddle.net/E5n7g.
I use the built-in
addEventListener()
to add an event on the "a tag", I then try and remove this using jQuery, however it seems jQuery can only unbind events its bound itself.
The reason I am asking this, is because I am trying to use jQuery on combination with a product which uses Dojo. When I bind the "click" event, its added to the list of event handlers however whenever I click that link its erasing that event handler and only leaving Dojo's intact.
One method I found that I used (and worked rather well) was the cloneNode function.
var new_el = el.cloneNode(true); //true means a deep copy
el.parentNode.replaceChild(new_el,el);
When you clone the element, it does not clone any events.

How to define events with JQuery using class or ids selectors before element has been loaded?

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/

jQuery clone() not cloning event bindings, even with on()

I have created a series of custom jQuery events for use in mobile web applications. They work great and have been tested. However, I have run into a small problem which I am having trouble understanding.
I am using .clone() on a few elements within the DOM, which contain a button. The button has some of the custom events bound to it (the events are bound using .on()), but. Unfortunately, when I use jQuery's .clone(), the bindings are not preserved, and I have to add them again.
Has anyone encountered this before, does someone know of a potential work around? I thought that using .on() was supposed to preserve the binding for elements that exist now, or in the future?
I think you should use this overload of the .clone() method:
$element.clone(true, true);
clone( [withDataAndEvents] [, deepWithDataAndEvents] )
withDataAndEvents: A Boolean indicating whether event handlers and data should be copied along with the elements. The default value is false.
deepWithDataAndEvents: A Boolean indicating whether event handlers and data for all children of the cloned element should be copied. By default its value matches the first argument's value (which defaults to false).
Beware that .on() does not actually bind the events to the targets but to the element you are delegating to. So if you have:
$('#container').on('click', '.button', ...);
The events are actually binded to #container. When a click on a .button element occurs, it bubbles up to the #container element The element which triggered the event is evaluated upon the selector parameter of .on() and if it matches, the event handler is executed. This is how event delegation works.
If you clone the element #container, you have to deep clone with events and data for the bindings made with .on() to be preserved.
This would not be necessary if you were using .on() on a parent of #container.

Are defining many jQuery event handlers "expensive?" Internally Implemented at C/C++ or JavaScript level?

I have a long a web form. I'm wondering if I should bind() to each <input> element separately (what I really want) or should I only define one bind() all of the input elements then do an if-then inside the handler to handle the specific element?
jQuery's event handlers are implemented in JavaScript (they have to be).
In general, it's best to use a single handler for the entire form, rather than a large number of individual elements. But jQuery's live feature can help quite a lot, it does a lot of the plumbing for event delegation for you. For example:
$("#formid input").live('focus', function(event) {
var field = $(this);
// `field` now references the field that was focussed
});
...watches all fields in your formid form for focus events. If you're using jQuery 1.4, that works even with the focus event in that example (even though focus doesn't bubble, and so is usually tricky to use with event delegation). Prior to 1.4 that won't work, but bubbling events like click and such do.
I would bind to all the inputs, but you can use classes to narrow it down to just the inputs you want.
Instead of
$("#formid input").click(function() {
if($(this).attr('something') == 'special_field') {
//do A
}
});
add a class to the elements you are interested in <input class='special_field' ... >, and change your selector:
$("#formid input.special_field").click(function() {
//do A
});
That will limit the handler to only the desired elements without any if statement checks.
You can repeat this for anything that needs special handling.
Final note on the .live() method. It can be really handy for a couple reasons:
It doesn't actually create a binding for every matching element, it creates a listener on the body element by default(you can choose another element as the listener) and waits for an even to bubble up to it. When it bubbles, it checks the triggered element against the selector, and if its a match fires the event.
Because the selector is applied when the event fires, it means that new elements added via Javascript or AJAX will fire the code without needing to bind or rebind them.
There is one listener for many elements, meaning for large sets it can be much quicker.

Categories

Resources