I have a number of jQuery scripts that select elements within the area that I run a partial page refresh on.
I am using this css tricks code snippet to refresh that part of the page:
$('#refreshbutton').click(function() {
var url = "http://myUrl.com/indexTest.php?ID=" + Math.random();
setTimeout(function() {
$("#maindisplay").load(url+" #maindisplay>*","");
}, 100);
});
The problem is that the elements within #maindisplay are changed, thus are considered new elements in the dom. Since the scripts that select those elements and attach functions to them run at domready and not during the partial refresh, this poses a problem.
So far I have been unable to find a way to reattach the scripts to the elements within #maindisplay after I partially refresh it.
My question is: What is the optimal way to reattach the scripts to the refreshed area of the page.
Thank you for any advice.
You need to use the live() function to attach your click handler.
You have the following options that I can think of:
Put the attach in a function and call that function on page refresh
Use the .live() functionality
Use .delegate() functionality
Put the Javascript reference to the functionality in a reference in the refresh so that it executes as a part of that refresh
Put the function in the callback
make it part of your setTimeout
some other creative method I did not think of...
Just a note: I would look at the .delegate() with contextual selection added in recent versions (available in 1.4.2 for instance).
Does load() not take a callback function as it's second argument? Why not reattach event handlers to the elements with that function?
$('#result').load('ajax/test.html', function() {
//reattach event handlers here.
});
Related
I have read code the uses jQuery outside of the ready handler, what are the drawbacks, if any to using it this way? For whatever reason I feel uncomfortable with it coded this way.
Inline script from and ASP.NET MVC View:
<script type="text/javascript">
function foo() {
if ($("#checkAll").attr("checked")) {
$(".setColumns").attr("checked", true);
}
else {
$(".setColumns").attr("checked", false);
}
}
</script>
There aren't really any drawbacks. It's just that you need to wait for the DOM element to be loaded before it can be manipulated. For example, if you had code like this:
<script type="text/javascript">
console.log($('#el').html());
</script>
<div id="el">Text</div>
The function would not return a value because the div was not yet loaded.
It is not.
The only reason why some people run it inside the document.ready handler, is because at that time, they can be sure the DOM tree is completely loaded, and your queries will return the correct results.
However, if you put your script tags underneath all elements, you normally would not have any issues with this.
The reason of using jQuery within the DOM ready handler is that event binding will only work when the element is present — if your DOM is not ready, your element may not be present and therefore the event may not be bound.
It is the same problem that people face when trying to bind events to dynamically loaded content without the .on() selector, for example — if the element is not initially present, events will not be bound to it.
p/s: You are of course free to define functions outside the handler.
I was told to use document.ready when I first started to use Javascript/jQuery but I never really learned why.
Might someone provide some basic guidelines on when it makes sense to wrap javascript/jquery code inside jQuery's document.ready?
Some topics I'm interested in:
jQuery's .on() method: I use the .on() method for AJAX quite a bit (typically on dynamically created DOM elements). Should the .on() click handlers always be inside document.ready?
Performance: Is it more performant to keep various javascript/jQuery objects inside or outside document.ready (also, is the performance difference significant?)?
Object scope: AJAX-loaded pages can't access objects that were inside the prior page's document.ready, correct? They can only access objects which were outside document.ready (i.e., truly "global" objects)?
Update: To follow a best practice, all my javascript (the jQuery library and my app's code) is at the bottom of my HTML page and I'm using the defer attribute on the jQuery-containing scripts on my AJAX-loaded pages so that I can access the jQuery library on these pages.
In simple words,
$(document).ready is an event which fires up when document is
ready.
Suppose you have placed your jQuery code in head section and trying to access a dom element (an anchor, an img etc), you will not be able to access it because html is interpreted from top to bottom and your html elements are not present when your jQuery code runs.
To overcome this problem, we place every jQuery/javascript code (which uses DOM) inside $(document).ready function which gets called when all the dom elements can be accessed.
And this is the reason, when you place your jQuery code at the bottom (after all dom elements, just before </body>) , there is no need for $(document).ready
There is no need to place on method inside $(document).ready only when you use on method on document because of the same reason I explained above.
//No need to be put inside $(document).ready
$(document).on('click','a',function () {
})
// Need to be put inside $(document).ready if placed inside <head></head>
$('.container').on('click','a',function () {
});
EDIT
From comments,
$(document).ready does not wait for images or scripts. Thats the big difference between $(document).ready and $(document).load
Only code that accesses the DOM should be in ready handler. If it's a plugin, it shouldn't be in the ready event.
Answers:
jQuery's .on() method: I use the .on() method for AJAX quite a bit
(dynamically creating DOM elements). Should the .on() click handlers
always be inside document.ready?
No, not always. If you load your JS in the document head you will need to. If you are creating the elements after the page loads via AJAX, you will need to. You will not need to if the script is below the html element you are adding a handler too.
Performance: Is it more performant to keep various javascript/jQuery
objects inside or outside document.ready (also, is the performance difference significant?)?
It depends. It will take the same amount of time to attach the handlers, it just depends if you want it to happen immediately as the page is loading or if you want it to wait until the entire doc is loaded. So it will depend what other things you are doing on the page.
Object scope: AJAX-loaded pages can't access objects that were inside
the prior page's document.ready, correct? They can only access objects
which were outside document.ready (i.e., truly "global" objects)?
It's essentially it's own function so it can only access vars declared at a global scope (outside/above all functions) or with window.myvarname = '';
Before you can safely use jQuery you need to ensure that the page is in a state where it's ready to be manipulated. With jQuery, we accomplish this by putting our code in a function, and then passing that function to $(document).ready(). The function we pass can just be an anonymous function.
$(document).ready(function() {
console.log('ready!');
});
This will run the function that we pass to .ready() once the document is ready. What's going on here? We're using $(document) to create a jQuery object from our page's document, and then calling the .ready() function on that object, passing it the function we want to execute.
Since this is something you'll find yourself doing a lot, there's a shorthand method for this if you prefer — the $() function does double duty as an alias for $(document).ready() if you pass it a function:
$(function() {
console.log('ready!');
});
This is a good reading: Jquery Fundamentals
.ready() - Specify a function to execute when the DOM is fully loaded.
$(document).ready(function() {
// Handler for .ready() called.
});
Here is a List of all jQuery Methods
Read on Introducing $(document).ready()
To be realistic, document.ready is not needed for anything else than manipulating the DOM accurately and it's not always needed or the best option. What I mean is that when you develop a large jQuery plugin for example you hardly use it throughout the code because you're trying to keep it DRY, so you abstract as much as possible in methods that manipulate the DOM but are meant to be invoked later on. When all your code is tightly integrated the only method exposed in document.ready is usually init where all the DOM magic happens. Hope this answers your question.
You should bind all actions in document.ready, because you should wait till the document is fully loaded.
But, you should create functions for all actions and call them from within the document.ready. When you create functions (your global objects), call them whenever you want. So once your new data is loaded and new elements created, call those functions again.
These functions are the ones where you've bound the events and action items.
$(document).ready(function(){
bindelement1();
bindelement2();
});
function bindelement1(){
$('el1').on('click',function...);
//you might make an ajax call here, then under complete of the AJAX, call this function or any other function again
}
function bindelement2(){
$('el2').on('click',function...);
}
I appended a link to a div and wanted to do some tasks on the click. I added the code below the appended element in the DOM but it did not work. Here is the code:
<div id="advance-search">
Some other DOM elements
<!-- Here I wanted to apppend the link as <span class="bold">x</span> Clear all-->
</div>
<script>
$("#advance-search #reset-adv-srch").on("click", function (){
alert('Link Clicked');``
});
</script>
It did not work. Then I placed the jQuery code inside $(document).ready and it worked perfectly. Here it is.
$(document).ready(function(e) {
$("#advance-search #reset-adv-srch").on("click", function (){
alert('Link Clicked');
});
});
he ready event occurs when the DOM (document object model) has been loaded.
Because this event occurs after the document is ready, it is a good place to have all other jQuery events and functions. Like in the example above.
The ready() method specifies what happens when a ready event occurs.
Tip: The ready() method should not be used together with .
I'm using a third-party commenting plugin, and I would like to change the content of some of the buttons. This is straightforward for buttons with id's known ahead of time, but it also has buttons that don't appear until a 'Reply' button is clicked. To be clear, these elements are not present when the page is loaded. They are inserted into the DOM following some event. For those elements, I only know a prefix of the id.
My first thought was to use .on, and to delegate to the children of the reply container, but the load event does not bubble, so this doesn't work:
<script>
$("#container").on("load", 'a[id|="reply-button"]', function(event) { $(this).html("different text"); } );
</script>
<div id="container">
<a id="reply-button-42das56ds6d78a">some text</a>
</div>
What's the next best thing?
"I know they will appear when the 'Reply' button is clicked. When that happens, new elements are inserted into the DOM, and I know what the prefix of the id of those elements will be."
You could use something like the DOMSubtreeModified event to tell when elements are added, but that isn't supported by all browsers. (In fact it has been deprecated.)
Or you could attach a click handler to the 'Reply' button:
$(document).ready(function() {
// initialise plugin here, then:
$("some selector for the reply button(s)").click(function(e) {
// setTimeout(function() {
$('a[id|="reply-button"]').html("different text");
// }, 10);
});
});
jQuery ensures that multiple event handlers will run in the order they are bound, but of course this only applies to handlers added with jQuery. So if the third-party commenting plugin you are using also uses jQuery then just be sure it is initialised first and your own reply click handler should run afterwards and at that time it will be able to access the elements added by the plugin.
If the plugin doesn't use jQuery you can't be sure your click handler will run last so instead uncomment the setTimeout code I've shown above - it will wait a few milliseconds to give the plugin events time to run and then update the text.
Use the selector $('#^=id')
id being the prefix
e.g all ids starting test123
$('#^=test123')
this would work for things like
test1234
test12345
test123fgjfdgj
This might help: http://oscarotero.com/jquery/
And use jquery event listeners for the page load..
e.g. $(document).ready(function(){});
If they are loaded when a button is clicked then do..
$('#buttonid').click(function() {//handle click});
You're looking for DOM Mutation Events. This spec allows you to be notified when DOM nodes are inserted, changed, etc. Browser support is not really there, though... well, IE is behind (IE >= 9 has support). It's also a major performance hog. See this MDN document. For these reasons, I don't think a lot of folks here would suggest using them. Here's some code, though:
document.addEventListener("DOMNodeInserted", function(e) {
if ($(e.target).is('selector matching new elements')) {
//do what you want with e.target, which is the newly-inserted element
}
}, false);
There is a performance-boosting hack involving listening for CSS animation events instead: here. Only problem is that IE9 does not support CSS animations. I think we're all waiting for the day when we can use these events in a cross-browser and performant way, though.
I have a fairly standard star voting functionality in my app that uses jQuery's hover event. The partial that the star voting logic is in used to be rendered with the rest of the page once the DOM was initially loaded (HTML request). However, I would like to move the partial so that it's not loaded with the page but can be loaded when the user wants. I made a typical AJAX request to load the partial but when it gets rendered the stars don't react properly to events like a mouseover. Is this issue being brought on because I'm rendering the forms via AJAX or is there just a bug in my code? Thanks for the help
Update: Got it working using the on handler, thanks for the help all!
You are likely trying to bind events to nodes that don't exist in the DOM yet. The best way to solve this is to bind to a listener that exists prior to the Ajax request, that is an ancestor (sometimes incorrectly called "parent", which is only one level of ancestor) of the content being fetched. For example, given this markup in the page itself:
<div id="ajaxContainer">
<!-- content will be periodically replaced with Ajax -->
</div>
"ajaxContainer" is an ancestor of whatever you're going to fetch. Then you need to bind a listener using an appropriate method. In the old days you could use live() but it's deprecated and was not so efficient anyhow. Then the recommendation was for delegate(), which solved efficiency problems. Now it's for a delegated listener syntax of on(), which is roughly the same performance as delegate() but with different syntax.
All that to say, use .on() if you are using jQuery 1.7+.
Imagine your Ajax function retrieves a portion of a page containing your star system mouseover, which is inside a series of divs classed as "stars". The syntax might look like:
$(document).ready(function() {
$('#ajaxContainer').on('mouseenter', '.stars', function() {
$this = $(this); // cache this specific instance of a stars div as a jQuery object
// do stuff with $this
});
});
This says "Start listening inside ajaxContainer for events that match 'mouse enters stars divs' and when that happens, do stuff."
The elements that are created with Ajax will not respond to your event handlers, as the event handlers only work on elements that are present in the DOM at the time of initializiation.
You need to delegate, and listen for events on elements that are present in the DOM, and catch the bubbling of the dynamic elements.
You should use on() for this:
$('#nonDynamicElement').on('mouseenter', '#dynamicElement', function() {
//do stuff
});
As from jQuery 1.7+ you should use on()
for older versions of jquery you can use live()
jQuery has a function called live which lets you apply event handlers to not yet created objects.
As said in the comment, use on() instead.
If your using jQuery within an AJAX script, be sure to use jQuery instead of $.
jQuery( selector [, context] )
Instead of
$( selector [, context] )
I have a problem that happens only on a specific computer(FFX 3.6.13,Windows 7,jQuery 1.4.3).
Sometimes document.ready is fired but when trying to get elements to attach the event handlers,the elements don't exist!
the code goes something like this:
$(function(){
window.initStart = true;
$("#id_of_element").click(function()...);
window.initEnd = $("#id_of_element");
});
the window.initStart/End are there for debugging,sometimes this code runs just fine,but sometimes window.initEnd is just a empty jQuery set(length == 0).
What this means is that document.ready is always fired,but sometimes it is fired before elements are available.
Does anybody had this problem? what could the problem be?
One way that you could try to get around this would be with using .live instead of .click. The following code
$('#idOfDiv').live('click', function() { doStuff(); });
will attach the input function to the click event of everything that is dropped on the page with an id of 'idOfDiv' as soon as it makes it to the page. Whereas .click executes immediately, this should be attached no matter what time the divs make it to the page.
Cheers
There's an article on SitePoint that demonstrates how to sense when certain dom elements are available.
Also I know this is a version specific issue, but if you were on Jquery 1.5 the deferred objects stuff would be useful here.