jquery functions dont work on dom elements loaded asynchromously - javascript

I wrote jQuery event handlers on DOM elements that are not yet in the page but might be loaded asynchronously into the page. What I observed was these event handlers seem to not recognize that some new elements were added to the DOM and that they need to act on them on triggering.
Am I right in my observation? How do I achieve this functionality?

If you want event handlers to work on dynamically added content, you need to use on
$(document).on("click", "someCssSelector", function(){
//your code here
});
Of course this will cause all clicks anywhere on your page to be watched. To be more efficient, see if you can structure your page so that all of these elements whose click event you want to handle will be in one container. ie, if all of these elements are going to be added to a div with an id of foo, you'd write the above more efficiently as
$("#foo").on("click", "someCssSelector", function(){
//your code here
});
If you're using jQuery < 1.7, you'd use delegate
$(document).delegate("someCssSelector", "click", function(){
//your code here
});

Am I right in my observation?
Yes.
How do I achieve this functionality?
Using the .on function to subscribe to those event handlers if you are using jQuery 1.7+:
$(document).on('click', '.someSelector', function() {
...
});
or using the .delegate function if you are using an older version (higher than 1.4.3):
$(document).delegate('.someSelector', 'click', function() {
...
});
For both you could use a more specific root than document to improve performance if you know that those elements will be added to some container for example.
And if you are using some prehistoric version you could go with .live():
$('.someSelector').live('click', function() {
...
});

Related

jQuery not taking effect right away [duplicate]

This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 8 years ago.
Suppose I have some jQuery code that attaches an event handler to all elements with class .myclass.
For example:
$(function(){
$(".myclass").click( function() {
// do something
});
});
And my HTML might be as follows:
<a class="myclass" href="#">test1</a>
<a class="myclass" href="#">test2</a>
<a class="myclass" href="#">test3</a>
That works with no problem.
However, consider if the .myclass elements were written to the page at some future time.
For example:
<a id="anchor1" href="#">create link dynamically</a>
<script type="text/javascript">
$(function(){
$("#anchor1").click( function() {
$("#anchor1").append('<a class="myclass" href="#">test4</a>');
});
});
</script>
In this case, the test4 link is created when a user clicks on a#anchor1.
The test4 link does not have the click() handler associated with it, even though it has class="myclass".
Basically, I would like to write the click() handler once and have it apply to both content present at page load, and content brought in later via AJAX / DHTML. Any idea how I can fix this?
I am adding a new answer to reflect changes in later jQuery releases. The .live() method is deprecated as of jQuery 1.7.
From http://api.jquery.com/live/
As of jQuery 1.7, the .live() method is deprecated. Use .on() to attach event handlers. Users of older versions of jQuery should use .delegate() in preference to .live().
For jQuery 1.7+ you can attach an event handler to a parent element using .on(), and pass the a selector combined with 'myclass' as an argument.
See http://api.jquery.com/on/
So instead of...
$(".myclass").click( function() {
// do something
});
You can write...
$('body').on('click', 'a.myclass', function() {
// do something
});
This will work for all a tags with 'myclass' in the body, whether already present or dynamically added later.
The body tag is used here as the example had no closer static surrounding tag, but any parent tag that exists when the .on method call occurs will work. For instance a ul tag for a list which will have dynamic elements added would look like this:
$('ul').on('click', 'li', function() {
alert( $(this).text() );
});
As long as the ul tag exists this will work (no li elements need exist yet).
Sometimes doing this (the top-voted answer) is not always enough:
$('body').on('click', 'a.myclass', function() {
// do something
});
This can be an issue because of the order event handlers are fired. If you find yourself doing this, but it is causing issues because of the order in which it is handled.. You can always wrap that into a function, that when called "refreshes" the listener.
For example:
function RefreshSomeEventListener() {
// Remove handler from existing elements
$("#wrapper .specific-selector").off();
// Re-add event handler for all matching elements
$("#wrapper .specific-selector").on("click", function() {
// Handle event.
}
}
Because it is a function, whenever I set up my listener this way, I typically call it on document ready:
$(document).ready(function() {
// Other ready commands / code
// Call our function to setup initial listening
RefreshSomeEventListener();
});
Then, whenever you add some dynamically added element, call that method again:
function SomeMethodThatAddsElement() {
// Some code / AJAX / whatever.. Adding element dynamically
// Refresh our listener, so the new element is taken into account
RefreshSomeEventListener();
}
Hopefully this helps!
Regards,
After jQuery 1.7 the preferred methods are .on() and .off()
Sean's answer shows an example.
Now Deprecated:
Use the jQuery functions .live() and .die(). Available in
jQuery 1.3.x
From the docs:
To display each paragraph's text in an
alert box whenever it is clicked:
$("p").live("click", function(){
alert( $(this).text() );
});
Also, the livequery plugin does this and has support for more events.
If you're adding a pile of anchors to the DOM, look into event delegation instead.
Here's a simple example:
$('#somecontainer').click(function(e) {
var $target = $(e.target);
if ($target.hasClass("myclass")) {
// do something
}
});
You can bind a single click event to a page for all elements, no matter if they are already on that page or if they will arrive at some future time, like that:
$(document).bind('click', function (e) {
var target = $(e.target);
if (target.is('.myclass')) {
e.preventDefault(); // if you want to cancel the event flow
// do something
} else if (target.is('.myotherclass')) {
e.preventDefault();
// do something else
}
});
Been using it for a while. Works like a charm.
In jQuery 1.7 and later, it is recommended to use .on() in place of bind or any other event delegation method, but .bind() still works.
Binds a handler to an event (like click) for all current - and future - matched element. Can also bind custom events.
link text
$(function(){
$(".myclass").live("click", function() {
// do something
});
});
If your on jQuery 1.3+ then use .live()
Binds a handler to an event (like
click) for all current - and future -
matched element. Can also bind custom
events.
You want to use the live() function. See the docs.
For example:
$("#anchor1").live("click", function() {
$("#anchor1").append('<a class="myclass" href="#">test4</a>');
});

Click event on appended content in some cases not working [duplicate]

This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 8 years ago.
Suppose I have some jQuery code that attaches an event handler to all elements with class .myclass.
For example:
$(function(){
$(".myclass").click( function() {
// do something
});
});
And my HTML might be as follows:
<a class="myclass" href="#">test1</a>
<a class="myclass" href="#">test2</a>
<a class="myclass" href="#">test3</a>
That works with no problem.
However, consider if the .myclass elements were written to the page at some future time.
For example:
<a id="anchor1" href="#">create link dynamically</a>
<script type="text/javascript">
$(function(){
$("#anchor1").click( function() {
$("#anchor1").append('<a class="myclass" href="#">test4</a>');
});
});
</script>
In this case, the test4 link is created when a user clicks on a#anchor1.
The test4 link does not have the click() handler associated with it, even though it has class="myclass".
Basically, I would like to write the click() handler once and have it apply to both content present at page load, and content brought in later via AJAX / DHTML. Any idea how I can fix this?
I am adding a new answer to reflect changes in later jQuery releases. The .live() method is deprecated as of jQuery 1.7.
From http://api.jquery.com/live/
As of jQuery 1.7, the .live() method is deprecated. Use .on() to attach event handlers. Users of older versions of jQuery should use .delegate() in preference to .live().
For jQuery 1.7+ you can attach an event handler to a parent element using .on(), and pass the a selector combined with 'myclass' as an argument.
See http://api.jquery.com/on/
So instead of...
$(".myclass").click( function() {
// do something
});
You can write...
$('body').on('click', 'a.myclass', function() {
// do something
});
This will work for all a tags with 'myclass' in the body, whether already present or dynamically added later.
The body tag is used here as the example had no closer static surrounding tag, but any parent tag that exists when the .on method call occurs will work. For instance a ul tag for a list which will have dynamic elements added would look like this:
$('ul').on('click', 'li', function() {
alert( $(this).text() );
});
As long as the ul tag exists this will work (no li elements need exist yet).
Sometimes doing this (the top-voted answer) is not always enough:
$('body').on('click', 'a.myclass', function() {
// do something
});
This can be an issue because of the order event handlers are fired. If you find yourself doing this, but it is causing issues because of the order in which it is handled.. You can always wrap that into a function, that when called "refreshes" the listener.
For example:
function RefreshSomeEventListener() {
// Remove handler from existing elements
$("#wrapper .specific-selector").off();
// Re-add event handler for all matching elements
$("#wrapper .specific-selector").on("click", function() {
// Handle event.
}
}
Because it is a function, whenever I set up my listener this way, I typically call it on document ready:
$(document).ready(function() {
// Other ready commands / code
// Call our function to setup initial listening
RefreshSomeEventListener();
});
Then, whenever you add some dynamically added element, call that method again:
function SomeMethodThatAddsElement() {
// Some code / AJAX / whatever.. Adding element dynamically
// Refresh our listener, so the new element is taken into account
RefreshSomeEventListener();
}
Hopefully this helps!
Regards,
After jQuery 1.7 the preferred methods are .on() and .off()
Sean's answer shows an example.
Now Deprecated:
Use the jQuery functions .live() and .die(). Available in
jQuery 1.3.x
From the docs:
To display each paragraph's text in an
alert box whenever it is clicked:
$("p").live("click", function(){
alert( $(this).text() );
});
Also, the livequery plugin does this and has support for more events.
If you're adding a pile of anchors to the DOM, look into event delegation instead.
Here's a simple example:
$('#somecontainer').click(function(e) {
var $target = $(e.target);
if ($target.hasClass("myclass")) {
// do something
}
});
You can bind a single click event to a page for all elements, no matter if they are already on that page or if they will arrive at some future time, like that:
$(document).bind('click', function (e) {
var target = $(e.target);
if (target.is('.myclass')) {
e.preventDefault(); // if you want to cancel the event flow
// do something
} else if (target.is('.myotherclass')) {
e.preventDefault();
// do something else
}
});
Been using it for a while. Works like a charm.
In jQuery 1.7 and later, it is recommended to use .on() in place of bind or any other event delegation method, but .bind() still works.
Binds a handler to an event (like click) for all current - and future - matched element. Can also bind custom events.
link text
$(function(){
$(".myclass").live("click", function() {
// do something
});
});
If your on jQuery 1.3+ then use .live()
Binds a handler to an event (like
click) for all current - and future -
matched element. Can also bind custom
events.
You want to use the live() function. See the docs.
For example:
$("#anchor1").live("click", function() {
$("#anchor1").append('<a class="myclass" href="#">test4</a>');
});

jQuery not working in Chrome but working on jsFiddle [duplicate]

This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 8 years ago.
Suppose I have some jQuery code that attaches an event handler to all elements with class .myclass.
For example:
$(function(){
$(".myclass").click( function() {
// do something
});
});
And my HTML might be as follows:
<a class="myclass" href="#">test1</a>
<a class="myclass" href="#">test2</a>
<a class="myclass" href="#">test3</a>
That works with no problem.
However, consider if the .myclass elements were written to the page at some future time.
For example:
<a id="anchor1" href="#">create link dynamically</a>
<script type="text/javascript">
$(function(){
$("#anchor1").click( function() {
$("#anchor1").append('<a class="myclass" href="#">test4</a>');
});
});
</script>
In this case, the test4 link is created when a user clicks on a#anchor1.
The test4 link does not have the click() handler associated with it, even though it has class="myclass".
Basically, I would like to write the click() handler once and have it apply to both content present at page load, and content brought in later via AJAX / DHTML. Any idea how I can fix this?
I am adding a new answer to reflect changes in later jQuery releases. The .live() method is deprecated as of jQuery 1.7.
From http://api.jquery.com/live/
As of jQuery 1.7, the .live() method is deprecated. Use .on() to attach event handlers. Users of older versions of jQuery should use .delegate() in preference to .live().
For jQuery 1.7+ you can attach an event handler to a parent element using .on(), and pass the a selector combined with 'myclass' as an argument.
See http://api.jquery.com/on/
So instead of...
$(".myclass").click( function() {
// do something
});
You can write...
$('body').on('click', 'a.myclass', function() {
// do something
});
This will work for all a tags with 'myclass' in the body, whether already present or dynamically added later.
The body tag is used here as the example had no closer static surrounding tag, but any parent tag that exists when the .on method call occurs will work. For instance a ul tag for a list which will have dynamic elements added would look like this:
$('ul').on('click', 'li', function() {
alert( $(this).text() );
});
As long as the ul tag exists this will work (no li elements need exist yet).
Sometimes doing this (the top-voted answer) is not always enough:
$('body').on('click', 'a.myclass', function() {
// do something
});
This can be an issue because of the order event handlers are fired. If you find yourself doing this, but it is causing issues because of the order in which it is handled.. You can always wrap that into a function, that when called "refreshes" the listener.
For example:
function RefreshSomeEventListener() {
// Remove handler from existing elements
$("#wrapper .specific-selector").off();
// Re-add event handler for all matching elements
$("#wrapper .specific-selector").on("click", function() {
// Handle event.
}
}
Because it is a function, whenever I set up my listener this way, I typically call it on document ready:
$(document).ready(function() {
// Other ready commands / code
// Call our function to setup initial listening
RefreshSomeEventListener();
});
Then, whenever you add some dynamically added element, call that method again:
function SomeMethodThatAddsElement() {
// Some code / AJAX / whatever.. Adding element dynamically
// Refresh our listener, so the new element is taken into account
RefreshSomeEventListener();
}
Hopefully this helps!
Regards,
After jQuery 1.7 the preferred methods are .on() and .off()
Sean's answer shows an example.
Now Deprecated:
Use the jQuery functions .live() and .die(). Available in
jQuery 1.3.x
From the docs:
To display each paragraph's text in an
alert box whenever it is clicked:
$("p").live("click", function(){
alert( $(this).text() );
});
Also, the livequery plugin does this and has support for more events.
If you're adding a pile of anchors to the DOM, look into event delegation instead.
Here's a simple example:
$('#somecontainer').click(function(e) {
var $target = $(e.target);
if ($target.hasClass("myclass")) {
// do something
}
});
You can bind a single click event to a page for all elements, no matter if they are already on that page or if they will arrive at some future time, like that:
$(document).bind('click', function (e) {
var target = $(e.target);
if (target.is('.myclass')) {
e.preventDefault(); // if you want to cancel the event flow
// do something
} else if (target.is('.myotherclass')) {
e.preventDefault();
// do something else
}
});
Been using it for a while. Works like a charm.
In jQuery 1.7 and later, it is recommended to use .on() in place of bind or any other event delegation method, but .bind() still works.
Binds a handler to an event (like click) for all current - and future - matched element. Can also bind custom events.
link text
$(function(){
$(".myclass").live("click", function() {
// do something
});
});
If your on jQuery 1.3+ then use .live()
Binds a handler to an event (like
click) for all current - and future -
matched element. Can also bind custom
events.
You want to use the live() function. See the docs.
For example:
$("#anchor1").live("click", function() {
$("#anchor1").append('<a class="myclass" href="#">test4</a>');
});

How to avoid multiple loading of jQuery functions?

I am using following code on my page which I am loading in ajax.
$(document).ready(function() {
$('#button_id').click(function() {
//Do Something
});
});
Now When I click on the button action happens multiple times. I know that its happening because I am loading the ajax page multiple times.
Please help me solve this.
You can use .off() to remove existing listeners:
$(function() {
$('#button_id').off('click').click(function() {
//Do Something
});
});
If I am wrong about your implementation I apologize. Your problem may exist because the binding is created on first page load and then on subsequent ajax loads with new scripts being inserted and creating duplicate bindings. You should prevent any bindings from being generated on ajax loads to prevent duplicate bindings unless you are good with cleanup.
If the button you are clicking on exists in the ajax loaded area then you should use delegation to ensure that the click handlers still work.
For example:
$( "body" ).on( "click", "#button_id", function() {
//do something
});
This will add a binding to the body element, but more specifically to the id #button_id. A click event on the button will propagate and bubble up to the body element (or whatever parent element you choose).
This makes it so that dynamic elements can be inserted in the DOM and only one event handler is needed to listen for it.
No need for .on() or .off() calls for individual ajax loads. This allows your bindings to be much cleaner.
Of course, if your button is not likely to exist on the page all the time then it would not be a good idea to keep extra bindings. Only create these types of binding if they are always needed to prevent optimization issues.
A cleaner solution would be to remove that code from the ajax loaded HTML and use one single event handler in the master page
I guess your problem is the event is firing many times.
To fire only once try this:
$(document).ready(function() {
$('#button_id').on("click",function(e) {
e.preventDefault(); // This prevents the default non-js action (very used for anchors without links or hashes)
e.stopPropagation(); // Prevent the bubling of the event and spread more times
//Do Something
});
});
If doesn't work with e.stopPropagation(); try with e.stopInmediatePropagation();
Adding documentation for the last method I suggested. It could solve your problem.
http://api.jquery.com/event.stopimmediatepropagation/

How do I unbind events properly when using allowSamePageTransition in jQuery Mobile?

I'm using the jQuery Mobile option allowSamePageTransition, which enables me to go from
page A > page A > page A ...
I need this to allow browsing through a catalogue of items. My problem is, the items need some form of interaction and I used to attach the interaction binding to document, because it is set before the elements affected are generated.
However, reloading the same page over and over again will re-bind my event handlers every time I reload.
My first idea was to use .off when the page is being hidden, but reloading a page #foo, will trigger pagehide on the same page being shown, so all bindings set on
$(document).on("pagebeforeshow.foo_events", "#foo", function(e) {
// bind when shown
});
will be unbound again by the previous #foo being hidden
$(document).on("pagehide", "#foo", function (e) {
$(this).off(".foo_events");
// removes bindings on #foo being hidden AND shown
});
The only solution I have come up with is plastering the document with classes, which I don't like doing:
priv.setBindings = function (param) {
var doc = $(document);
doc
.filter(function() { return $(this).is(".e_gallery") !== true; })
.on("pagebeforeshow.gallery", param.pageId, function (e) {
doc.addClass(".e_gallery");
// run stuff
});
};
But I'm no fan of attaching classes to the dom.
Question:
Is there a way to prevent multiple event bindings set on $(document) when going to the same page over and over again WITHOUT toggling classes?
Solution 1
Best solution would be to use pageinit to bind events. If you take a look at an official documentation you will find out that pageinit will trigger ONLY once, just like document ready, so there's no way events will be bound again. This is best solution because you don't have processing overhead like when removing events with off method.
Working jsFiddle example: http://jsfiddle.net/Gajotres/AAFH8/
Of course this will fail in case multiple HTML solution is used.
Solution 2
Remove event before you bind it:
$(document).on('pagebeforeshow', '#index', function(){
$(document).off('click', '#test-button').on('click', '#test-button',function(e) {
alert('Button click');
});
});
Working jsFiddle example: http://jsfiddle.net/Gajotres/K8YmG/
Solution 3
Use a jQuery Filter selector, like this:
$('#carousel div:Event(!click)').each(function(){
//If click is not bind to #carousel div do something
});
Because event filter is not a part of official jQuery framework it can be found here: http://www.codenothing.com/archives/2009/event-filter/
This is probably best solution because event is going to be bound ONLY once.
Solution 4
Probably an easiest of them all.
$(document).on('pagebeforeshow', '#index', function(){
$(document).on('click', '#test-button',function(e) {
if(e.handled !== true) // This will prevent event triggering more then once
{
alert('Clicked');
e.handled = true;
}
});
});
Working jsFiddle example: http://jsfiddle.net/Gajotres/Yerv9/
This is a 180 percent different solution then solution 3, in this case event is going to be bound numerous times but it will be allowed to execute only once.
More info
If you want to find more about this problem take a look at this article, working examples are included.

Categories