jQuery: is delegating always better than direct functions binding - javascript

Is always better to use $(document).on('click', selector, fn) than $(selector).click(fn), since the 1st choice:
1) can handle dynamically created element
2) is faster during page load.. right? (since JS doesn't have to spend time querying and binding function to each selector)
Is it safe to forget about direct binding and always go for delegation?

.on()
Advantages
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. The document element is available in the head of the document before loading any other HTML, so it is safe to attach events there without waiting for the document to be ready.
In addition to their ability to handle events on descendant elements not yet created, another advantage of delegated events is their potential for much lower overhead when many elements must be monitored.
Performance
Attaching many delegated event handlers near the top of the document
tree can degrade performance. Each time the event occurs, jQuery must
compare all selectors of all attached events of that type to every
element in the path from the event target up to the top of the
document. For best performance, attach delegated events at a document
location as close as possible to the target elements. Avoid excessive
use of document or document.body for delegated events on large
documents.
.click()
This method is a shortcut for .on( "click", handler )

With my research, I come to a conclusion that a good delegate method is better than the direct binding. Let's talk from the begging. We know that dom event will bubble up from the target element to it's parent, grandparent until to the document. Though there are a little difference among IE and other browsers, Jquery event creates consistent cross-browser behavior. Thus, the obvious difference between the two methods is that:
Direct bind event will occur on the target (or from its descendants) and bubble up to document, while delegation just bubble up to the outmost bind target. Consider the example:
$("#myBtn").click(function(){
console.log("button was clicked");
});
document.onclick = function(){
console.log("document is clicked");
}
<div id="testDiv" style="background:darkgrey">
<button type="button" id="testBtn">click me</button>
</div>
When click the button, document.onclick will be triggered.
However, if replace with the delegate method like:
$("#myDiv").on("click", "#myBtn", function(){
console.log("myBtn was clicked");
});
The document.onclick will not be triggered. Meanwhile, notice that click on the outmost myDiv will not trigger the event.
Here comes to the key point. Using the delegate method in a good manner will improve the performance hugely. See this example (mutated from professional javascript for web developer):
<ul id="myLinks">
<li id="goSomewhere"> Go somewhere </li>
<li id="doSomething"> Do something </li>
<li id="sayHi"> Say hi </li>
</ul>
The traditional direct bind way would be:
$("#goSomewhere").click(function(){
window.location.href = "http://sample.com";
});
$("#doSomething").click(function(){
window.title = "I change the title";
});
$("#sayHi").click(function(){
alert("hi");
});
If there are many click events, numbers of bind operation will consume a lot of memory as well as a long page initial time. We can subtract to just one bind operation with delegation:
$("#myLink").on("click", function(event){
switch(event.target.id){
case: "goSomewhere":
window.location.href = "http://sample.com";
break;
case: "doSomething":
window.title = "title was changed";
break;
case: "sayHi":
alert("hi");
break;
}
});
This reduce much memory to use. To be more practical, you may need to use a object to replace switch-case module for the performance, if there are lots of cases, like:
var eventHandler = {
goSomewhere: function(){ window.location = "http://sample.com"; },
doSomething: function(){ window.title = "title changed"; },
sayHi: function(){alert("hi"); }
}
$("#myLink").on("click", function(event){
if(eventHandler[event.target.id]) eventHandler[event.target.id]();
});
Because javascript's object is actually a hash table.
Then, there comes an idea: just attach a single event to the document to handle all of the events. It's practical to events like mousedown, click, keydown and so on, not fit for mouseout, mousein. The advantage is clear: we just bind a event causing less memory, easy to remove the event handler, need not to wait for the document ready event as document has been be visible since it's child script is read. In contact, if you just bind every single event to document, the advantage will be gone.
Additionally, there is a trap if using direct bind, the example is from jquery: Considering a table with 1000 rows:
$( "#dataTable tbody tr" ).on( "click", function() {
console.log( $( this ).text() );
});
This will attach a hander to 1000 tr! But the following one just a single attachment to tbody:
$( "#dataTable tbody" ).on( "click", "tr", function() {
console.log( $( this ).text() );
});

Related

.on() event handler inside ajaxComplete()?

I have this:
$('.task').on('click', function()
{
task_id = $(this).data('id');
console.log('Task id: ' + task_id);
});
But this doesn't work as it should when the content is reloaded via ajax. task_id value stays the same even after clicking different elements after the ajax reload. Apparently I have to bind it to the body first.
This is how it is in my code right now though (it works as expected):
$(document).ajaxComplete(function(event, xhr, settings) {
$('.task').on('click', function()
{
task_id = $(this).data('id');
console.log('Task id: ' + task_id);
});
});
But I've been told this duplicates/doubles the trigger for the .on('click') event? Is this true? How do I know then when to bind to the direct selector or bind to the document.body instead?
Which would be more efficient? Binding to body or putting the event delegation inside ajaxComplete()?
I'm a little confused too since I have other event handlers inside the same .js file but outside ajaxComplete() that seem to work just fine even after an ajax reload?
You should use .on() method with Event Delegation approach, when generating elements dynamically(content is updated via $.ajax())/manipulating selectors. then you won't need to attach event handler in ajaxComplete()
General Syntax
$(document).on('event','selector',callback_function)
Example
$(document).on('click', '.task', function(){
//Rest of your code
});
In place of document you should use closest static container.
The 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, we can use delegated events to bind the click event to dynamically created elements and also to avoid the need to frequently attach and remove event handlers.

Event handler query at time that event is registered?

I know certain queries take a bit longer than others (e.g., compound queries are slower than simple queries, ids are faster than classes, etc.). In my case, that's of practical significance. Wonder how it applies to queries in event handlers.
Does the query have any impact on the speed at which the event handler will fire? Or is the query already resolved to some sort of pointer to that object in the DOM?
For example, would these handlers be absolutely equivalent? :
$("body > section > #id div.class element").click(func);
$("#element").click(func);
In the case you give, the speed of the selector would only affect the initial setup of the page -- the speed to find the element on which to place the event handler. Once the event handler is attached, the selector shouldn't affect the speed of the actual event handler firing.
The case in which selector speed could matter to an event handler would be where you use the on() function to define event handlers for elements that might not yet exist -- "delegated" events. For example:
$( "#dataTable tbody" ).on( "click", "tr", func);
versus
$( "#dataTable tbody" ).on( "click", ".my-table-row", func);
The performance of the first event handler will be better (though it's absolutely worth pointing out that the difference is typically small). The reason this case is different from your example is that the actual click handler is being placed on the tbody, and the selector is then used at fire time to determine whether a given event is a match.

jquery delete dynamically created input field

So im creating project in which you can create unlimited number of input fields that belong to the same array and eventualy are being posted to php handler via ajax. i managed to get that far, its working all fine but the problem im having is that i would want to let user to delete input he/she doesnt want (i.e. created by mistake), it seems to be core part of script, yet i dont know how to approach the issue.
This project you can see in here:
http://jsfiddle.net/7LCzN/
and this is the code:
$(function(){
$("#add").on('click', function () {
$('body').append('<input type="text" class="ac" name="array[]" />');
});
});
$(function(){
$("#post").on('click', function () {
var myArray = new Array();
$('.ac').each(function(index, elem) {
myArray.push($(elem).val());
});
$('#result').text(myArray);
});
});
So for instance ive created 4 fields with these value:
5463, 8675, 2340, 1203
and i just realized i dont want the one with value 2340 i would want to delete it so im left with 3 fields:
5463, 8675, 1203
anyone that helps, ill be glad and greatful, thank you fellows:)
.remove() is a jQuery function that you can use to remove elements from the DOM.
Here's a tiny example:
$(".inputToRemove").remove();
Here's a fork of your jsFiddle for a working example.
From the docs:
Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the call to .on(). To ensure the elements are present and can be selected, perform event binding inside a document ready handler for elements that are in the HTML markup on the page. If new HTML is being injected into the page, select the elements and attach event handlers after the new HTML is placed into the page. Or, use delegated events to attach an event handler, as described next.
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 element could be the container element of a view in a Model-View-Controller design, for example, or document if the event handler wants to monitor all bubbling events in the document. The document element is available in the head of the document before loading any other HTML, so it is safe to attach events there without waiting for the document to be ready.
In addition to their ability to handle events on descendant elements not yet created, another advantage of delegated events is their potential for much lower overhead when many elements must be monitored. On a data table with 1,000 rows in its tbody, this example attaches a handler to 1,000 elements:
$( "#dataTable tbody tr" ).on( "click", function() {
alert( $( this ).text() );
});
A delegated-events approach attaches an event handler to only one element, the tbody, and the event only needs to bubble up one level (from the clicked tr to tbody):
$( "#dataTable tbody" ).on( "click", "tr", function() {
alert( $( this ).text() );
});

Jquery events, simple clicks, how and why?

So i have some data on a page (a table) which based on some options elsewhere may get ajax reloaded from the server.
This table has buttons in it that can be clicked to make other things happen to the records in the table.
I notice that this ...
http://api.jquery.com/on/
... is the recommended approach for attaching simple event handlers to elements but that only attaches to elements that exist right now, and when I do my ajax load I lose the attached handlers.
So I started using this ... http://api.jquery.com/live/ ... and guess what, jquery team did their usual and deprecated it saying I should be using "on".
These functions behave very differently yet jquery docs say i should be using them interchangably so ...
Can someone explain the "on" equivelent of this and how I can get it to work with elements after an ajax call replacing the elements that hae previously been attached to ...
$("some selector").live('click', function (e) {
// some code code
e.preventDefault();
return false;
});
My understanding is that you would do something like ...
$("some selector").on('click', function (e) {
// some code code
e.preventDefault();
return false;
});
My guess is that I then have to re-run this code after performing my ajax call by putting this in to some sort of "initClicks" function and calling it both on page load and after the ajax call.
This seems to be a bit of a back step to me ... or have i missed something here?
Since the elements are added dynamically, you need to use event delegation to register the event handler
// New way (jQuery 1.7+) - .on(events, selector, handler)
$(document).on('click', 'some selector', function(event) {
// some code code
e.preventDefault();
return false;
});
Also, either use e.preventDefault() or return false, as:
return false = e.preventDefault() + e.stopPropagation()
So, there is no need to use both of them at same time.
When you use .on('click', function (e) {}) function, it works only for existing elements.
To handle click event on all selector elements, even for elements which will be added in future, you can use one of these functions:
$(document).on('click', "some selector", function (e) {
// some code code
e.preventDefault();
return false;
});
or:
$("body").delegate("a", "click", function () {
// your code goes here
});
For more information read article about Understanding Event Delegation
live() is not magic, it cannot see future elements, what it was doing is to attach a listener to the first root element of your page document and checks every bubbled event if it match your target selector, and when it find a match, it executes your function.
this is called event delegation
live() has been deprecated for good reasons, mainly the performance hit caused by using it.
then the jQUery team introduced the delegate() function which gave us a new way to achieve the exact result, but it has addressed the performance hit very cleverly by limiting the scope in which it will listen to bubbled events to the possible nearest parent of your now & future elements.
when they introduced the On() function, they gave you the ability to use it as normal event handler, or as a delegated handler for future elements.
so I believe they did a good job for this, giving us the flexibility to use it as we wish according to the specific scenario.
Code Examples:
using delegate():
$( "#TAGERT_ID" ).delegate( "a", "click", function() { // your code goes here}
using on() (for delegated events)
$( "#TAGERT_ID" ).on( "click", "a", function() { // your code goes here}
both ways are the same, and will handle future clicks on a which will be added in the future inside your TARGET_ID element.
TARGET_ID is an example for using ID for your selector, but you can use whatever selector according to your specific need.
The equivalent of said live is
$(document).on('click', "some selector", function (e) {
// some code code
e.preventDefault();
return false;
});
The on() is a single stop for all event handler formats, the model you used is the same as
$("some selector").click(function (e) {
// some code code
e.preventDefault();
return false;
});
which does work based event delegation.
You can never actually attach event listener to an element which does not exist in DOM yet. What live and on method do is attach listener on a parent which exists right now. live is nothing but an on attached on document itself.

Bind ready event on javascript dom element creation

i would like to know if we can bind a loaded or ready event on an item created by a script when the dom is loaded. I heard from live() but it's not something clickable, it's just an item which has to load.
Thanks for your help!
I guess your best shot is the load event there.
$('element').load(function(){
alert('loaded');
});
native
var elem = document.getElementById('element_id');
elem.onload = function(){
alert('loaded');
};
Another example for dynamic creation:
$('<img/>', {
src: '/images/myimage.png',
load: function(){
alert('image loaded');
}
}).appendTo(document.body);
If you want to be able to separate the pieces of code for creating the item and the load event handling you could try having your dynamically created element trigger a custom event on the window:
var myElement = $('<img/>', {
src: '/images/myimage.png'
}).appendTo(document.body);
$(window).trigger( {type: "myElementInit", myObject : myElement} );
With a pointer back to itself in the extra parameters, you could then have a separate handler set-up within a jQuery(document).ready to look for the "myElementInit" window event and grab the reference to the element out of the extra parameters:
jQuery.('window').bind( "myElementInit", function(event){
var theElement = event.myObject;
...
} );
You can use the delegated form of the .on() event, as documented here:
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
element could be the container element of a view in a
Model-View-Controller design, for example, or document if the event
handler wants to monitor all bubbling events in the document. The
document element is available in the head of the document before
loading any other HTML, so it is safe to attach events there without
waiting for the document to be ready.

Categories

Resources