This part of code is an answer from this question.
$(document.body).on('change', 'select[name^="income_type_"]', function() {
alert($(this).val());
});
I Have two questions the first one is.
Is there a performance issue selecting 'document.body' instead of selecting the Parent element of select?
Something like this.
Second question is.
It will be function like '$.live()' when putting Parent element instead of document.body?
$("#IdOfParentHere").on('change', 'select[name^="income_type_"]', function() {
alert($(this).val());
});
Thanks!
There could be a performance impact(not much significant though) when attaching event handlers to body instead parent element.
Take a case where you are trying to delegate a click event, what you really want to is to handle dynamically created li elements which are in a static ul element. In event delegation when an event happens inside the attached element that events target will be evaluated against the delegation selector to see whether to trigger the handler. In this case if the event is attached to the ul only events inside the ul has to be tested, but if the hanlder is attached to body all the click in the page will have to be tested.
The live() method attaches the handler to the document object, so yes it will be similar to that.
This method provides a means to attach delegated event handlers to the
document element of a page, which simplifies the use of event handlers
when content is dynamically added to a page.
Is there a performance issue selecting 'document.body' instead of selecting the Parent element of select?
No. There is no significant difference in performance. Of course it would be a little faster if you put it closer on the DOM, but we are talking about an incalculably small difference.
Second question is. It will be function like '$.live()' when putting Parent element instead of document.body?
$.live does exactly the same thing as $("body").on("click", "selector",
Related
I am trying to understand this particular difference between the direct and delegated event handlers using the jQuery .on() method. Specifically, the last sentence in this paragraph:
When a selector is provided, the event handler is referred to as delegated. The handler is not called when the event occurs directly on the bound element, but only for descendants (inner elements) that match the selector. jQuery bubbles the event from the event target up to the element where the handler is attached (i.e., innermost to outermost element) and runs the handler for any elements along that path matching the selector.
What does it mean by "runs the handler for any elements"? I made a test page to experiment with the concept. But both following constructs lead to the same behavior:
$("div#target span.green").on("click", function() {
alert($(this).attr("class") + " is clicked");
});
or,
$("div#target").on("click", "span.green", function() {
alert($(this).attr("class") + " is clicked");
});
Maybe someone could refer to a different example to clarify this point? Thanks.
Case 1 (direct):
$("div#target span.green").on("click", function() {...});
== Hey! I want every span.green inside div#target to listen up: when you get clicked on, do X.
Case 2 (delegated):
$("div#target").on("click", "span.green", function() {...});
== Hey, div#target! When any of your child elements which are "span.green" get clicked, do X with them.
In other words...
In case 1, each of those spans has been individually given instructions. If new spans get created, they won't have heard the instruction and won't respond to clicks. Each span is directly responsible for its own events.
In case 2, only the container has been given the instruction; it is responsible for noticing clicks on behalf of its child elements. The work of catching events has been delegated. This also means that the instruction will be carried out for child elements that are created in future.
The first way, $("div#target span.green").on(), binds a click handler directly to the span(s) that match the selector at the moment that code is executed. This means if other spans are added later (or have their class changed to match) they have missed out and will not have a click handler. It also means if you later remove the "green" class from one of the spans its click handler will continue to run - jQuery doesn't keep track of how the handler was assigned and check to see if the selector still matches.
The second way, $("div#target").on(), binds a click handler to the div(s) that match (again, this is against those that match at that moment), but when a click occurs somewhere in the div the handler function will only be run if the click occurred not just in the div but in a child element matching the selector in the second parameter to .on(), "span.green". Done this way it doesn't matter when those child spans were created, clicking upon them will still run the handler.
So for a page that isn't dynamically adding or changing its contents you won't notice a difference between the two methods. If you are dynamically adding extra child elements the second syntax means you don't have to worry about assigning click handlers to them because you've already done it once on the parent.
The explanation of N3dst4 is perfect. Based on this, we can assume that all child elements are inside body, therefore we need use only this:
$('body').on('click', '.element', function(){
alert('It works!')
});
It works with direct or delegate event.
Tangential to the OP, but the concept that helped me unravel confusion with this feature is that the bound elements must be parents of the selected elements.
Bound refers to what is left of the .on.
Selected refers to the 2nd argument of .on().
Delegation does not work like .find(), selecting a subset of the bound elements. The selector only applies to strict child elements.
$("span.green").on("click", ...
is very different from
$("span").on("click", ".green", ...
In particular, to gain the advantages #N3dst4 hints at with "elements that are created in future" the bound element must be a permanent parent. Then the selected children can come and go.
EDIT
Checklist of why delegated .on doesn't work
Tricky reasons why $('.bound').on('event', '.selected', some_function) may not work:
Bound element is not permanent. It was created after calling .on()
Selected element is not a proper child of a bound element. It's the same element.
Selected element prevented bubbling of an event to the bound element by calling .stopPropagation().
(Omitting less tricky reasons, such as a misspelled selector.)
I wro te a post with a comparison of direct events and delegated. I compare pure js but it has the same meaning for jquery which only encapsulate it.
Conclusion is that delegated event handling is for dynamic DOM structure where binded elements can be created while user interact with page ( no need again bindings ), and direct event handling is for static DOM elements, when we know that structure will not change.
For more information and full comparison -
http://maciejsikora.com/standard-events-vs-event-delegation/
Using always delegated handlers, which I see is current very trendy is not right way, many programmers use it because "it should be used", but truth is that direct event handlers are better for some situation and the choice which method use should be supported by knowledge of differences.
Case 3 (delegated):
$("div#target").delegate("span.green", "click", function() {...});
is there any difference between this both selectors in combination with a click event?
$("#container").find(".element").on("click",function(){
})
$("#container").on("click", ".element",function(){
})
For me I think technically the effect and consequence will be the same?
Thank you
They are not the same.
The first example using find().on() looks for the .element class in the DOM and adds the event handler to it. It will not work for any elements with that class that are added to the DOM later in the page lifecycle.
The second example using on() with a selector is a delegated event handler, and will therefore work for all matching elements in the DOM as well as those added later.
I always wondered which is the better way of handling events in terms of code manageability, cleanliness and code reuse.
If you use the former then say a list of 10 anchor tags with click handler will have something like:
Click Me
Click Me
Click Me
... 10 times
which looks kind of odd.
With the latter method, using anonymous function, it'd be like:
$('a').on('click', function(e){});
At the end of the day, every event is bound to some element in the DOM. In the case of .bind, you're binding directly to the element (or elements) in your jQuery object. If, for example, your jQuery object contained 100 elements, you'd be binding 100 event listeners.
In the case of .live, .delegate, and .on, a single event listener is bound, generally on one of the topmost nodes in the DOM tree: document, document.documentElement (the element), or document.body.
Because DOM events bubble up through the tree, an event handler attached to the body element can actually receive click events originating from any element on the page. So, rather than binding 100 events you could bind just one.
For a small number of elements (fewer than five, say), binding the event handlers directly is likely to be faster (although performance is unlikely to be an issue). For a larger number of elements, always use .on.
The other advantage of .on is that if you add elements to the DOM you don't need to worry about binding event handlers to these new elements. Take, for example, an HTML list:
<ul id="todo">
<li>buy milk</li>
<li>arrange haircut</li>
<li>pay credit card bill</li>
</ul>
Next, some jQuery:
// Remove the todo item when clicked.
$('#todo').children().click(function () {
$(this).remove()
})
Now, what if we add a todo?
$('#todo').append('<li>answer all the questions on SO</li>')
Clicking this todo item will not remove it from the list, since it doesn't have any event handlers bound. If instead we'd used .on, the new item would work without any extra effort on our part. Here's how the .on version would look:
$('#todo').on('click', 'li', function (event) {
$(event.target).remove()
})
Second method is preferrable, since we should not be mixing our JavaScript with the HTML. (Separation of Concerns) . This way your code is kept clean.
This also works well with dynamically inserted HTML code.
`$('a').on('click', function(e){});` // Using jQuery.
Using Vanilla JS:
document.getElementById("idName").addEventListener("click", function(){}); // Bind events to specific element.
document.addEventListener("click", function(){}); // Bind events to the document. Take care to handle event bubbling all the way upto the document level.
I apologize if the question is formulated sloppy. I'm just somewhere in the beginning of understanding jquery.
I want to implement a form builder based on drag and drop.
I added button to clone dropped element.
But after cloning "remove" and "clone" buttons are not working.
jsfiddle.net/284mx1vn/
Thanks for your help!
I've just adjusted your Fiddle
I've added the two lines
$(document).on("click", ".remove", function(){
$(this).closest(".input-block").remove();});
$(document).on("click", ".add", function(){
$(this).closest(".input-block").clone().appendTo("#drop-space");
});
so it works for dynamically created elements, and added the class "add" to the "add"-button for convenience.
The issue was/is that events have to be bound to elements already existing in the DOM when the document is loaded. As solution it is possible to use event delegation - meaning to delegate the event (in this case the click event for the buttons) from a static parent element, e.g. $(document). This parent element will delegate the event to all children of the class using the jquery on() function, even if these elements are added later.
For reference: http://api.jquery.com/on/ and https://api.jquery.com/on/#on-events-selector-data-handler, section "Direct and delegated events":
"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()."
I have a set of three elements. And there are many coming elements after the page load by ajax when the user clicks on a certain element. I iterate over initial elements with each and attach an event to them like this:
tagSet.each(function(index, element){
tagSet.eq(index).on("click",function(){alert("Alerted! Clicked")});
}
But with this approach those ajax-created elements would not be attached with an event. Thus I have to make a little bit of change to on() for it accommodate the ajax-created elements:
tagSet.each(function(index, element){
$(document).on("click",tagSet.eq(index),function(){alert("Alerted! Clicked")});
}
It solve the problem of event attachment to those ajax-created elements but raises another issue. It attaches the event in a way that all of the elements of the page gets trigged with that specific event at once. I mean, since I have three elements, a click on one of them cause all three alert("Alerted!Clicke!) to trigger. What is the issue and the solution?
Use event delegation to bind to all current and future items that match a query:
$(document).on("click", ".some-class-here", function(){
alert("Alerted! Clicked")
});
Replace .some-class-here with a selector that matches your tagSet elements. Then remove your call to $.each.