jQuery on() event only working with $(document) - javascript

I'm using jQuery's .on() event handler and it's only working when I use $(document).
This works:
$(function() {
$(document).on("click", ".search .remove", function(e) {
console.log("clicked");
});
});
This does not work:
$(function() {
$(".search .remove").on("click", function(e) {
console.log("clicked");
});
});
Nothing happens on that second one...no errors or anything. It just doesn't fire.

You are using two different syntaxes of .on which have two very different outcomes.
Your first is:
$(context).on("event","targetselector",handler)
This binds the event to context, and any events of type event that gets to the context that has an e.target that can be selected with targetselector will trigger the handler with e.target as the context. this is commonly known as event delegation.
Your second syntax is
$(targetselector).on("event",handler)
In this case, the event is bound directly to the elements currently on the page that match targetselector, not future elements. This is essentially the same as the old .bind.

Your second example doesn't work because your elements are created dynamically. When using .on() with dynamically inserted elements, you have to bind it via an element that isn't inserted dynamically, i.e. one that exists on the page at load time.
You can continue to use document as an ancestor element but in terms of performance you might want to find an element closer in the DOM to ".search .remove".
From the jQuery docs on .on():
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.

Your first method is the on() equivalent for the deprecated method live(). Probably your elements get inserted dynamically after the page loading has finished.
You could rewrite your code like following and it should work:
$(function() {
$(".search").on("click", ".remove", function(e) {
console.log("clicked");
});
});

Related

jQuery on load not firing (not Ajax)

At the outset, let me be clear I'm not trying to use load() in an Ajax context to load a remote resource.
I'm just trying to bind a function to an object that doesn't exist at page load time, such that I can do stuff to it when it does appear.
I'm using jQuery 1.7
I have a form with class="contact-form").
This form is created on the fly, so it doesn't exist when document.ready() fires.
What I want to do is make some stuff happen when the form is created.
Presumably there should be a "load" or "ready" or some such event fired when the thing is available.
Under previous versions of jQuery I'd have used delegate() or live(); but these have been deprecated, and the current documentation says to use on( "load", handler ) or its shortcut, load().
I'm getting this from https://api.jquery.com/load-event/.
All of the following have so far failed to work:
$(".contact-form").load(function(){
console.log("Hi there!");
});
and
$(".contact-form").on("load", function(){
console.log("Hi there!");
});
and, in a hail-mary based on ideas from Jquery event handler not working on dynamic content,
$(document.body).on("load", ".contact-form", function(){
console.log("Hi there!");
});
Any pointers appreciated.
If you use .load() which is a shortcut for .on('load') called the load event, the matching element (form in this case) must exist at the time the page was loaded. jQuery < 1.7 had a .live() function which would listen for new elements dynamically added to the page, but it was removed in jQuery 1.7 for various reasons, performance being a major one.
Other options
jQuery LiveQuery is a plugin that sounds like it will do exactly what you're looking for.
https://github.com/brandonaaron/livequery
jQuery Entwine will watch for new DOM elements using livequery, but also allows you to create DOM elements and use them as full objects with their own methods defined.
https://github.com/hafriedlander/jquery.entwine
More info from jQuery's .on() docs
You can use Delegated events to create a click handler which will fire when an element is dynamically added to your original selector (typically a container), such as:
$( "#dataTable tbody" ).on( "click", "tr", function() {
alert( $( this ).text() );
});
Now, when a new <tr> is added dynamically, it will have the click handler bound to it. However, there is no event for the actual loading of an element into the DOM.
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.
Why do you need an event at all? If the form is being added dynamically then run what you need to at the time
var form = '<form class="contact-form"></form>';
$('body').append(form);
console.log("Hi there!");
This method is a shortcut for .on( "load", handler ).
The load event is sent to an element when it and all sub-elements have been completely loaded. This event can be sent to any element associated with a URL: images, scripts, frames, iframes, and the window object.
For example, consider a page with a simple image:
<img src="book.png" alt="Book" id="book">
The event handler can be bound to the image:
$( "#book" ).load(function() {
// Handler for .load() called.
});
As soon as the image has been loaded, the handler is called.
Now put that inside a ready handler
$( document ).ready(function() {
// onload functions here
});

Click event not triggered of dynamically added div

I have added a div dynamically into HTML,
When i have tried to trigger the click event of same element
what i have tried till yet is below ::
$(function(){
$("#id").bind("click",function(){
alert("hi");
})
});
i have also tried to use "on" instead of "bind" but it doesn't work.
but when i have write simple , it works fine
<div onclick="javascript:testFunction();"></div>
Delegate event using on(), you can give the static parent of element that is supposed to be added after execution of binding code.
$(function(){
$(document).on("click", "#id",function(){
alert("hi");
});
});
Delegated events
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, reference.

JQuery selectors missunderstanding

I'm trying to make a simple tree-view script, and start with opening/closing nodes. But I stuck with some problem:
$(function() {
$('#tree li.closedNode').on('click',function(e){
e.stopPropagation();
$(this).removeClass('closedNode').addClass('openedNode').children(':not(a.caption)').show();
})
$('#tree li.openedNode').on('click',function(e){
e.stopPropagation();
$(this).addClass('closedNode').removeClass('openedNode').children(':not(a.caption)').hide();
})
jsfiddle: http://jsfiddle.net/F33dS/14/
So, then you click on 'click here' it's closing, changing class, but it still firing event for 'li.openedNode'. I know, that I missed somthing simple, but what? I really can't find the problem. So, why it's working in this way?
You're binding event to things that don't exist yet.
You need to use .on() such that it targets all matching elements whether they exist now or in the future.
http://jsfiddle.net/F33dS/16/
$('#tree').on('click', 'li.closedNode', function(e){
e.stopPropagation();
$(this).removeClass('closedNode').addClass('openedNode').children(':not(a.caption)').show();
})
$('#tree').on('click', 'li.openedNode', function(e){
e.stopPropagation();
$(this).addClass('closedNode').removeClass('openedNode').children(':not(a.caption)').hide();
})
Your nodes have the class openNode on page load.
The script looks for $('#tree li.openNode') and matches elements.
The script looks for $('#tree li.closedNode') and matches none.
It's only when the user clicks the element that a match would be found for $('#tree li.closedNode').
So we tell its parent which exists to look for the click event for both matching descendants. As soon as one MATCHING descendant pops into existence (when you change the class name), the event triggers.
From http://api.jquery.com/on/
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.
In your original code you set up the correct selector, but there were no matches at that time. So, #tree which exists at the time, can store the events made on its descendants.
Just one other thing
Why hide and show the list elements with jQuery? You're adding a class anyway so you could do that with CSS.

The added class doesn't trigger its jQuery function

It's an audio player: the idea is that the play button turns into a pause button (and viceversa) when clicked.
Thing is that the .pause event doesn't trigger the following function:
$('.pause').click(function(){
player.pause();
$(this).addClass('play');
$(this).removeClass('pause');
});
The css shows that the pause class is set, but the function doesn't work. Is there a way to make it work? (would be great to know why it didn't work)
jsFiddle
Use a delegated event binding to bind a handler that will be selector-aware without requiring rebinding on events.
For the purposes of your demo, the selector would be along the lines of:
$('.player_controls').on('click', '.pause', function () {...});
Delegate event bindings attach the listener to a parent element that checks to see if the event fired was fired on an element that matches the provided selector.
jQuery docs
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.
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.
You can use event delegation for this. The issue is that binding directly (without delegation) binds to whichever elements exist at the time click is called.
$(".player_controls").on("click", ".pause", function(){
/* ... */
});
Instead of using $('.pause').click(function(){...}) you would need to start using the $.on method to start listening for objects which are still not in the DOM.
e.g
$(".pause").parent().on("click",".pause", function(event){
player.pause();
$(this).addClass('play');
$(this).removeClass('pause');
});

Use jquery inside or outside document ready

Below two scenario give me the same behavior. But What is the difference technically? (I put the below code in the last section of script tags in the body.)
$(document).ready(function() {
$('.collapse').collapse({toggle: false});
$(document).on('click', '#expandAllLessons', function() {
$('div.accordion-body').collapse('show');
});
$(document).on('click', '#collapseAllLessons', function() {
$('div.accordion-body.collapse').collapse('hide');
});
});
or
$(document).ready(function() {
$('.collapse').collapse({toggle: false});
});
$(document).on('click', '#expandAllLessons', function() {
$('div.accordion-body').collapse('show');
});
$(document).on('click', '#collapseAllLessons', function() {
$('div.accordion-body.collapse').collapse('hide');
});
Thanks.
More or less, it's doing the same thing.
With the use of .on() with a child selector, you're using event delegation to bind any future events to any elements that match that selector. document is the very tippy top of the DOM tree (and available upon script execution), so your event delegation works.
.ready() waits until the DOM has assembled, so you can, more reliably, directly bind events using methods like .click(), .hover(), etc.
So your first example is just waiting for the DOM to assemble, then delegating the event. The second example is just delegating the event immediately upon script execution.
From jQuery's documentation regarding .on():
Direct and delegated events
The majority of browser events bubble, or
propagate, from the deepest, innermost element (the event target) in
the document where they occur all the way up to the body and the
document element. In Internet Explorer 8 and lower, a few events such
as change and submit do not natively bubble but jQuery patches these
to bubble and create consistent cross-browser behavior.
If selector is omitted or is null, the event handler is referred to as
direct or directly-bound. The handler is called every time an event
occurs on the selected elements, whether it occurs directly on the
element or bubbles from a descendant (inner) element.
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.
Whenever you do a function, regardless of whether it's $(document).ready(function(){}); or something else, all the contents inside that function can only read stuff that's at its level or above it (unless you're using return functions).
The top paragraph means that all your code won't be executed until it's loaded, but it also means that it's nested code. Nested code means certain variables and functions won't be readable from outside. Example:
function bob(){
function sandy(){
function joe(){
alert("I can access anything written by sandy, bob or ray!");
}
}
}
function ray(){
alert("I can't see anything from anybody but bob!");
}
Look at the comments first. After jQuery 1.7 on can delegate events as well:
"The .on() method attaches event handlers to the currently selected
set of elements in the jQuery object. As of jQuery 1.7, the .on()
method provides all functionality required for attaching event
handlers. For help in converting from older jQuery event methods, see
.bind(), .delegate(), and .live()."
So before jQuery 1.7 this is the correct answer:
First is better because, document ready event is triggered when HTML document is fully loaded to DOM. And then you're sure you have all elements in place, and you can bind events to them.
But if you bind event before loading '#expandAllLessons' element to DOM, then it will simply not work, as jQuery selector will not find any elements, and will not bind this event anywhere.
After 1.7 both will work almost in the same way. Almost, because in first case, when you trigger event before document will be ready, it will not be executed. In second example it will be executed, because it was attached when script was loaded.

Categories