Handling code which relies on jQuery before jQuery is loaded - javascript

I'd like to follow the general guideline of putting all JavaScript at the very bottom of the page, to speed up loading time and also to take care of some pesky issues with conflicting jQuery versions in a web app (Django).
However, every so often I have some code, code which depends on jQuery, but which must be further up on the page (basically the code can't be moved to the bottom).
I'm wondering if there's an easy way to code this so that even though jQuery is not yet defined the code works when jQuery is defined.
The following seems, I have to say, like overkill but I don't know of another way to do it:
function run_my_code($) {
// jquery-dependent code here
$("#foo").data('bar', true);
}
var t = null;
function jquery_ready() {
if (window.jQuery && window.jQuery.ui) {
run_my_code(window.jQuery);
} else {
t = window.setTimeout(jquery_ready, 100);
}
}
t = window.setTimeout(jquery_ready, 100);
Actually, I might need to use code more than once in a page, code that doesn't know about other code, so even this probably won't work unless I rename each jquery_ready to something like jquery_ready_guid, jquery_ready_otherguid and so on.
Clarification
Just so this is clear, I am putting the include to JavaScript (<script type="text/javascript" src="jquery.min.js" />) at the very bottom of the page, just before the </body>. So I can't use the $.

Simple use pure javascript version of $(document).ready();:
document.addEventListener("DOMContentLoaded", function(event) {
//you can use jQuery there
});

Your way is the only way that I know of, though I would ensure that the scoping is a little tighter:
(function() {
var runMyCode = function($) {
// jquery-dependent code here
$("#foo").data('bar', true);
};
var timer = function() {
if (window.jQuery && window.jQuery.ui) {
runMyCode(window.jQuery);
} else {
window.setTimeout(timer, 100);
}
};
timer();
})();
Update
Here's a little deferred loader I cobbled together:
var Namespace = Namespace || { };
Namespace.Deferred = function () {
var functions = [];
var timer = function() {
if (window.jQuery && window.jQuery.ui) {
while (functions.length) {
functions.shift()(window.jQuery);
}
} else {
window.setTimeout(timer, 250);
}
};
timer();
return {
execute: function(onJQueryReady) {
if (window.jQuery && window.jQuery.ui) {
onJQueryReady(window.jQuery);
} else {
functions.push(onJQueryReady);
}
}
};
}();
Which would then be useable like so:
Namespace.Deferred.execute(runMyCode);

The best way I have found is to write the code in a function and call the function after jquery is loaded:
function RunAfterjQ(){
// Codes that uses jQuery
}
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript">
RunAfterjQ();
</script>
Update: For master pages, you can define an array to push functions in the head of the master page:
var afterJQ = [];
then at the bottom of master page run all the functions pushed in to this array:
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript">
for(var i = 0; i < afterJQ.length; i++) afterJQ[i]();
</script>
Everywhere that you need to use javascript that relies on jQuery and is before jQuery is defined just push it in to this array:
afterJQ.push( function() {
// this code will execute after jQuery is loaded.
});

Here is a way to write injected code that will be run only after jQuery loads (whether synchronously or asynchronously).
<script>
if ( ! window.deferAfterjQueryLoaded ) {
window.deferAfterjQueryLoaded = [];
Object.defineProperty(window, "$", {
set: function(value) {
window.setTimeout(function() {
$.each(window.deferAfterjQueryLoaded, function(index, fn) {
fn();
});
}, 0);
Object.defineProperty(window, "$", { value: value });
},
configurable: true
});
}
window.deferAfterjQueryLoaded.push(function() {
//... some code that needs to be run
});
</script>
What this does is:
Defines deferAfterjQueryLoaded lazily, so you don't need to inject that into head.
Defines a setter for window.$. When jQuery loads, one of the last things it does is assign to the global $ variable. This allows you to trigger a function when that happens.
Schedules the deferred functions to run as soon as possible after the jQuery script finishes (setTimeout(..., 0);).
Has the setter remove itself.
For complete cleanliness you could have the scheduled function remove deferAfterjQueryLoaded as well.

How about:
<script>
window.deferAfterjQueryLoaded = [];
window.deferAfterjQueryLoaded.push(function() {
//... some code that needs to be run
});
// ... further down in the page
window.deferAfterjQueryLoaded.push(function() {
//... some other code to run
});
</script>
<script src="jquery.js" />
<script>
$.each(window.deferAfterjQueryLoaded, function(index, fn) {
fn();
});
</script>
This works because every script here is completely blocking. Meaning the creation of the deferAfterjQueryLoaded array and all functions being created and pushed to that array occur first. Then jQuery completely loads. Then you iterate through that array and execute each function. This works if the scripts are in separate files as well just the same way.
If you ALSO want DOMReady to fire you can nest a $(function() {}) inside of one of your deferAfterjQueryLoaded functions like such:
window.deferAfterjQueryLoaded.push(function() {
$(function() {
console.log('jquery loaded and the DOM is ready');
});
console.log('jquery loaded');
});
Ultimately, you should really refactor your code so everything is actually down at the bottom, and have a system conducive to that model. It is much easier to understand everything occurring and more performant (especially if you have separate scripts).

I have this same problem, but with a ton of files, I use headjs to manage the loading, it's only 2kb so there isn't really a problem, for me anyway, of putting in the header. Your code then becomes,
head.ready(function(){
$...
});
and at the bottom of the page,
head.js('/jquery.min.js');

You should be able to do this on a document ready event.

function jQueryGodot(code)
{
if (window.jQuery)
{
code(window.jQuery);
}
else
{
if (!window.$)
{
window.$ = { codes: [] };
window.watch('$', function(p, defered, jQuery) {
jQuery.each(defered.codes, function(i, code) {
code(jQuery);
});
return jQuery;
});
}
window.$.codes.push(code);
}
}
jQueryGodot(function($) {
$('div').html('Will always work!');
})
Working example on JSFiddle.
Code passed to jQueryGodot function will always be executed no matter if it is called before or after jQuery is loaded.
The solution relies on Object.watch which requires this polyfill (660 bytes minified) in most of the browsers: https://gist.github.com/adriengibrat/b0ee333dc1b058a22b66

You can defer all calls like jQuery(function(){...}) without the loop of a setTimeout: https://jsfiddle.net/rL1f451q/3/
It is collecting every jQuery(...) call into an array until jQuery is not defined, then the second code executes them when jQuery is available.
Put this in the head or the beginning of the body:
<!-- jQuery defer code body: deferring jQuery calls until jQuery is loaded -->
<script>
window.jQueryQ = window.jQueryQ || [];
window.$ = window.jQuery = function(){
window.jQueryQ.push(arguments);
}
</script>
<!-- end: jQuery defer code body -->
And this at the very end of the body, after the jQuery script:
<!-- jQuery deferring code footer: add this to the end of body and after the jQuery code -->
<script>
jQuery(function(){
jQuery.each(window.jQueryQ||[],function(i,a){
// to understand why setTimeout 0 is useful, see: https://www.youtube.com/watch?v=8aGhZQkoFbQ, tldr: having a lot of calls wont freeze the website
setTimeout(function(){
jQuery.apply(this,a);
},0);
});
});
</script>
<!-- end: jQuery deferring code footer -->

I've wrote simple js code for handle such cases: https://github.com/Yorkii/wait-for
Then you can use it like this
waitFor('jQuery', function () {
//jQuery is loaded
jQuery('body').addClass('done');
});
You can even wait for multiple libraries
waitFor(['jQuery', 'MyAppClass'], function () {
//Both libs are loaded
});

I'm posting my answer using a JavaScript promise. It works, it is simple and reusable.
The advantage is, that the code get's executed as soon as jQuery is loaded, no matter how early or late on the page.
But, I'm by far not as experienced like some other people in this thread. So I'd love my answer to be peer reviewed. I'd like to know if it really is a valid solution and what the downsides are.
Write an objectExists function with a promise as high up in the code as you want.
function jqueryExists() {
return new Promise(function (resolve, reject) {
(function waitForJquery() {
if (jQuery) return resolve();
setTimeout(waitForJquery, 30);
})();
});
}
Then add your function which depends on jQuery. As far as I understand, it won't block any other script from execution, and the page will load just fine even if jQuery is loaded much later.
jqueryExists().then(function(){
// Write your function here
}).catch(function(){
console.log('jQuery couldn\'t be loaded');
})
jQuery can now be loaded after this code, and the function will execute as soon as jQuery is available.

Related

Defer functions until jQuery has loaded (or another fixed point)

Question: is there anything wrong with using the following method to defer running code until after jQuery has loaded (or until another fixed point)?
Bonus question: is there a better way to do it? (E.g. not having to name the functions in window.deferred, like window.deferred.afunction)
In my page (before jQuery):
<script>
window.deferred = window.deferred || {};
window.deferred.afunction = function() {
console.log('afunction is running');
};
window.deferred.anotherfunction = function() {
console.log('anotherfunction is running');
};
</script>
In my JS (after jQuery when I'm ready to execute my deferred functions):
/* Run deferred functions */
if(window.deferred && typeof window.deferred === 'object') {
for (var fn in window.deferred) {
if (typeof window.deferred[fn] == 'function') {
window.deferred[fn]();
}
}
}
Demo: https://jsfiddle.net/j4sqy5kf/4/
As far as I can tell it works fine. But I consider myself amateur at JavaScript - I can write it but don't always understand how it's working.
So far all the ways I've found to do this (e.g. http://snipplr.com/view/54863/) rely on having setTimeout or setInterval and calling a check function, which seems quite inelegant to me.
There's also Require.js, which I believe could be used, but I think it's overkill to achieve exactly what I want as it primarily serves a different purpose.
Background
I'm writing a post for my blog in Markdown, and I'm writing a little JavaScript inside the page to manage some hidden content. I want to use jQuery in my script, but jQuery is loaded in the footer - so, I want an elegant way to defer execution of my inline script until after jQuery has loaded.
I have jQuery in my footer and a general.js script, in which most of the rest of my JavaScript runs. I'd like to run the 'In my page' bits inside each blog post, and leave the 'In my JS' bit in general.js so I never have to worry about it again.
I know I could define but not execute the functions, but I don't want to have to update general.js each time (e.g. add function1(), function2(), etc.)
I want it to automatically loop through all deferred functions.
I don't really see anything wrong with doing it this way. I would however use an array instead of an object:
/* Run deferred functions */
if(window.deferred && Array.isArray(window.deferred)) {
window.deferred.forEach(function (fn) {
if (typeof fn === 'function') {
fn();
}
});
}
.hello-world {
color: #f00;
font-size: 3em;
font-family: verdana;
}
.jq {
color: #00f;
}
<script>
window.deferred = window.deferred || [];
window.deferred.push(function aFunction() {
console.log('aFunction is running');
});
window.deferred.push(function anotherfunction () {
console.log('anotherfunction is running');
});
window.deferred.push(function doSomethingWithJquery () {
jQuery('<div class="hello-world">Hello from <span class="jq">jQuery</span>!</div>').appendTo('body');
});
</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
If you ever are looping over an object with for...in like your original code does, you should use hasOwnProperty to check that the object actually contains that property and you are not getting a property from the prototype chain.
An easier way of achieving what you want is by using DOMContentLoaded.
<script>
window.addEventListener('DOMContentLoaded', function() {
$( document ).ready(function() {
console.log('my other scripts including jquery has loaded now');
});
});
</script>
But I would stop and think about the reason for preferring inline scripts instead of your general.js, as inline scripts has a negative impact on performance, and prevents caching. If it is code separation you're after, you can achieve it by other means, depending on your setup.

Is it possible to pre-register handlers before jQuery is loaded?

The situation where jQuery is loaded late on the page but javascript that relies on jQuery being available is loaded before jQuery is a pretty common scenario, especially if you follow the practice of putting your scripts closer to </body>.
So basically I want to go from this:
<script>
someFunctionThatUsesLateJQuery(){ [code that relies on jQuery] }
</script>
...
<script src="jquery.js"></script>
<script>
$(function(){
someFunctionThatUsesLateJQuery();
});
</script>
To something like this:
<script>
_$.ready(function(){ [code that relies on jQuery] });
</script>
...
<script src="jquery.js"></script>
Much like asynchronous stats tracking (รก la Google Analytics), is there anything out there that allows you to register javascript function calls to be executed once jQuery is loaded without getting the dreaded $ is undefined error?
I mean for this to happen without registering and deregistering timeouts/intervals.
Has there ever been/is there the possibility of adding some sort of pre-registration variable to jQuery that it recognises and handles once it's loaded?
Use case:
It's worth noting that the specific use-case I've got is a drop-in JS widget, where I want some DOM manipulation to happen at the scene of the <script> placement, which therefore has the very real possibility of appearing before jQuery has loaded in the case of jQuery loading happening near </body>.
I then don't want to burden the user further by requiring them to register a specific function call at the correct point in code execution (which will be dependent on their implementation)... I want it to "just work"
As suggested here by rich.okelly you could try this:
(function() {
var runMyCode = function($) {
// jquery-dependent code here
$("#foo").data('bar', true);
};
var timer = function() {
if (window.jQuery && window.jQuery.ui) {
runMyCode(window.jQuery);
} else {
window.setTimeout(timer, 100);
}
};
timer();
})();
I also found a more complex solution, but I personally prefer the above solution over this solution.
Update without timeout:
<script>
var runMyCode = function($) {
// jquery-dependent code here
$("#foo").data('bar', true);
};
</script>
...
<script src="jquery.js"></script>
<script>
$(function(){
runMyCode(window.jQuery);
});
</script>
You could try to use common and popular solution when all your function calls moved to data-attributes. Then, when jQuery is loaded, you go throw all the DOM elements with such attributes and run this functions.
I.e. instead of function call you add data-type='load' data-function='YourNamespace.yourFunctionName' and after window.load event you select all the elements by $('[data-type="load"]'), iterates them, and perform function calls.
UPD: Guess, async function queuing pattern could be usefull to read about:
What's the name of Google Analytics async design pattern and where is it used?
If you inject the jQuery script include, then you can listen for the onload event.
function loadJS(url, onloadCallback, elId){
//Inject script include into HEAD
var scriptEl = document.createElement('script');
scriptEl.type = 'text/javascript';
scriptEl.src = url;
if(elId)scriptEl.id = elId;
document.getElementsByTagName('head')[0].appendChild(scriptEl);
if(onloadCallback){
scriptEl.onload = scriptEl.onreadystatechange = function(){
if(!scriptEl.readyState || (scriptEl.readyState === 'complete' || scriptEl.readyState === 'loaded')){
onloadCallback();
scriptEl.onload = scriptEl.onreadystatechange = null;
}
}
}
}
loadJS("http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js", function(){
console.log( window.$ );
});
Perhaps I don't understand the use case fully, but RequireJS sounds like it might be a good option for you:
https://github.com/requirejs/example-jquery-shim
define(["jquery", "jquery.alpha", "jquery.beta"], function($) {
//the jquery.alpha.js and jquery.beta.js plugins have been loaded.
$(function() {
$('body').alpha().beta();
});
});

execute function after complete page load [duplicate]

This question already has answers here:
How to make JavaScript execute after page load?
(25 answers)
Closed 1 year ago.
I am using following code to execute some statements after page load.
<script type="text/javascript">
window.onload = function () {
newInvite();
document.ag.src="b.jpg";
}
</script>
But this code does not work properly. The function is called even if some images or elements are loading. What I want is to call the function the the page is loaded completely.
this may work for you :
document.addEventListener('DOMContentLoaded', function() {
// your code here
}, false);
or
if your comfort with jquery,
$(document).ready(function(){
// your code
});
$(document).ready() fires on DOMContentLoaded, but this event is not being fired consistently among browsers. This is why jQuery will most probably implement some heavy workarounds to support all the browsers. And this will make it very difficult to "exactly" simulate the behavior using plain Javascript (but not impossible of course).
as Jeffrey Sweeney and J Torres suggested, i think its better to have a setTimeout function, before firing the function like below :
setTimeout(function(){
//your code here
}, 3000);
JavaScript
document.addEventListener('readystatechange', event => {
// When HTML/DOM elements are ready:
if (event.target.readyState === "interactive") { //does same as: ..addEventListener("DOMContentLoaded"..
alert("hi 1");
}
// When window loaded ( external resources are loaded too- `css`,`src`, etc...)
if (event.target.readyState === "complete") {
alert("hi 2");
}
});
same for jQuery:
$(document).ready(function() { //same as: $(function() {
alert("hi 1");
});
$(window).load(function() {
alert("hi 2");
});
NOTE: - Don't use the below markup ( because it overwrites other same-kind declarations ) :
document.onreadystatechange = ...
I'm little bit confuse that what you means by page load completed, "DOM Load" or "Content Load" as well? In a html page load can fire event after two type event.
DOM load: Which ensure the entire DOM tree loaded start to end. But not ensure load the reference content. Suppose you added images by the img tags, so this event ensure that all the img loaded but no the images properly loaded or not. To get this event you should write following way:
document.addEventListener('DOMContentLoaded', function() {
// your code here
}, false);
Or using jQuery:
$(document).ready(function(){
// your code
});
After DOM and Content Load: Which indicate the the DOM and Content load as well. It will ensure not only img tag it will ensure also all images or other relative content loaded. To get this event you should write following way:
window.addEventListener('load', function() {...})
Or using jQuery:
$(window).on('load', function() {
console.log('All assets are loaded')
})
If you can use jQuery, look at load. You could then set your function to run after your element finishes loading.
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.
});
If you need all elements on the current window to load, you can use
$(window).load(function () {
// run code
});
If you cannot use jQuery, the plain Javascript code is essentially the same amount of (if not less) code:
window.onload = function() {
// run code
};
If you wanna call a js function in your html page use onload event. The onload event occurs when the user agent finishes loading a window or all frames within a FRAMESET. This attribute may be used with BODY and FRAMESET elements.
<body onload="callFunction();">
....
</body>
You're best bet as far as I know is to use
window.addEventListener('load', function() {
console.log('All assets loaded')
});
The #1 answer of using the DOMContentLoaded event is a step backwards since the DOM will load before all assets load.
Other answers recommend setTimeout which I would strongly oppose since it is completely subjective to the client's device performance and network connection speed. If someone is on a slow network and/or has a slow cpu, a page could take several to dozens of seconds to load, thus you could not predict how much time setTimeout will need.
As for readystatechange, it fires whenever readyState changes which according to MDN will still be before the load event.
Complete
The state indicates that the load event is about to fire.
This way you can handle the both cases - if the page is already loaded or not:
document.onreadystatechange = function(){
if (document.readyState === "complete") {
myFunction();
}
else {
window.onload = function () {
myFunction();
};
};
}
you can try like this without using jquery
window.addEventListener("load", afterLoaded,false);
function afterLoaded(){
alert("after load")
}
Alternatively you can try below.
$(window).bind("load", function() {
// code here });
This works in all the case. This will trigger only when the entire page is loaded.
window.onload = () => {
// run in onload
setTimeout(() => {
// onload finished.
// and execute some code here like stat performance.
}, 10)
}
If you're already using jQuery, you could try this:
$(window).bind("load", function() {
// code here
});
I can tell you that the best answer I found is to put a "driver" script just after the </body> command. It is the easiest and, probably, more universal than some of the solutions, above.
The plan: On my page is a table. I write the page with the table out to the browser, then sort it with JS. The user can resort it by clicking column headers.
After the table is ended a </tbody> command, and the body is ended, I use the following line to invoke the sorting JS to sort the table by column 3. I got the sorting script off of the web so it is not reproduced here. For at least the next year, you can see this in operation, including the JS, at static29.ILikeTheInternet.com. Click "here" at the bottom of the page. That will bring up another page with the table and scripts. You can see it put up the data then quickly sort it. I need to speed it up a little but the basics are there now.
</tbody></body><script type='text/javascript'>sortNum(3);</script></html>
MakerMikey
I tend to use the following pattern to check for the document to complete loading. The function returns a Promise (if you need to support IE, include the polyfill) that resolves once the document completes loading. It uses setInterval underneath because a similar implementation with setTimeout could result in a very deep stack.
function getDocReadyPromise()
{
function promiseDocReady(resolve)
{
function checkDocReady()
{
if (document.readyState === "complete")
{
clearInterval(intervalDocReady);
resolve();
}
}
var intervalDocReady = setInterval(checkDocReady, 10);
}
return new Promise(promiseDocReady);
}
Of course, if you don't have to support IE:
const getDocReadyPromise = () =>
{
const promiseDocReady = (resolve) =>
{
const checkDocReady = () =>
((document.readyState === "complete") && (clearInterval(intervalDocReady) || resolve()));
let intervalDocReady = setInterval(checkDocReady, 10);
}
return new Promise(promiseDocReady);
}
With that function, you can do the following:
getDocReadyPromise().then(whatIveBeenWaitingToDo);
call a function after complete page load set time out
setTimeout(function() {
var val = $('.GridStyle tr:nth-child(2) td:nth-child(4)').text();
for(var i, j = 0; i = ddl2.options[j]; j++) {
if(i.text == val) {
ddl2.selectedIndex = i.index;
break;
}
}
}, 1000);
Try this jQuery:
$(function() {
// Handler for .ready() called.
});
Put your script after the completion of body tag...it works...

How do I load a variable number of scripts with jQuery.getScript() before running javascript code?

I need to load a variable number of javascript source files before running javascript code that depends on them. Sometimes 1 script needs to be loaded, other times 2. The getScript() method allows one script to be loaded - how could I use it to load x number of scripts before running its inner code?
$.getScript("test.js", function(){
// code to run after script is loaded
});
What I need:
$.getScript(new Array("1.js","2.js"), function(){
// code to run after all scripts are loaded
});
Thanks
If you are using jquery 1.5 you can use the new deferred syntax.
$.when(
$.getScript("1.js"),
$.getScript("2.js"),
$.getScript("3.js")
).then(function(){
alert("all loaded");
});
Just pass in the scripts you wish to load.
I suggest you look into LABjs
That is exactly what its purpose is.
I've use RequireJS quite extensively and it's very good. However, this might work for you:
$.getScript("1.js", function(){
$.getScript("2.js", function () {
// code to run after all scripts are loaded
});
});
That's a pretty nasty and little block of code there, IMO, but if it is actually only two scripts like that, it's probably worth it. The logic of the above could also be extracted to a generic function, but once you go too far down that path, it's probably smarter to use RequireJS, or LABjs as JAAulde suggested.
One way is to list all your scripts in an array, track how many scripts have loaded vs. the amount you want to load. Something like this:
var toLoad = ["1.js", "2.js", "3.js"], loaded = 0;
var onLoaded = function() {
loaded++;
if (loaded == toLoad.length) {
console.log('All scripts loaded!');
} else {
console.log('Not all scripts are loaded, waiting...');
}
}
for (var i = 0, len = toLoad.length; i < len; i++) {
$.getScript(toLoad[i], onLoaded);
}
Wrote this earlier tonight, but I promise I'm not a plant. ;-) In addition to LabJS and RequireJS, there's also Head.js which is dead simple to use and does exactly what you want.
Loading multiple scripts by $.getScript() one after the other and do stuff after all the scripts are loaded
Working Fiddle. Check the Console window for the output
We can create a function to which we pass array of js file paths, this function will do a $.getScript() for the first js file and on success method it will call the same function by passing the second js file index, and this on success will call the same function by passing 3rd file index and so on until it loads the last file. So its basically a recursion function which will give a callback when all the files in the array has been loaded.The end code would be as simple as
LoadAllScripts("yourArray",function(){
alert("all scripts loaded!!");
});
So the complete code would go like this.
var LoadAllScripts = function (scriptArray, callback) {
SyncLoadScript({ scriptArray: scriptArray, index: 0}, function () {
callback();
});
};
And SyncLoadScript (core of the logic) looks like
var SyncLoadScript = function (scriptConfig, callback) {
var $this = this;
var script = scriptConfig.scriptArray[scriptConfig.index];
if (scriptConfig.scriptArray.length > scriptConfig.index) {
if (script.trim().length > 0) {
$.getScript(script, function () {
console.log(script);
SyncLoadScript({ scriptArray: scriptConfig.scriptArray, index: ++scriptConfig.index, element: scriptConfig.element }, callback);
}).fail(function (jqXHR, textStatus, errorThrown) {
console.log(script + " failed while loading");
debugger;
console.log("Error: "+errorThrown);
SyncLoadScript({ scriptArray: scriptConfig.scriptArray, index: ++scriptConfig.index, element: scriptConfig.element }, callback);
});
}
else {
console.log("invalid script src!!");
}
}
else {
callback();
}
}
Then you can make a simple call to LoadAllScripts by passing array of js file path. like below.
LoadAllScripts(["1.js","2.js","3.js","4.js"], function () {
console.log("All the scripts have been loaded.");
//do your stuff after all the scripts are loaded.
});
Note: I have given empty callbacks for you guys to make tweaks and pass around any data of choice. probably to hold all the failed scripts that you can passback to the main function and try to reload them again.

Trigger $document.ready (so AJAX code I can't modify is executed)

My requirements are the following:
I've got a rich webpage that at a certain moment loads a bunch of HTML in a div, via AJAX.
The HTML I retrieve does have javascript (<script>...</script>)
The retrieved javascript contains $('document').ready( ... ) parts
I can not modify the retrieved javascript; it comes from an external lib
I've got a javascript function that is called when the AJAX is loaded. I'm trying to "trick it" into executing by doing:
function AjaxLoaded() {
$('document').trigger('ready');
}
That doesn't cut it, I'm afraid.
I've seen several responses on Stack Overflow that "evade" this question by changing the code that is returned on the AJAX (make it a function and call it after loading, or just remove the $(document).ready()). I need to stress out that I can't change the retrieved code on this case.
Afer some research i created a way to get it to work.
here is my test that shows it working: http://www.antiyes.com/test/test2.php
here is the relevant code:
<script>
// easy copy of an array
Array.prototype.copy = function() {
return [].concat(this);
};
// this function is added to jQuery, it allows access to the readylist
// it works for jQuery 1.3.2, it might break on future versions
$.getReadyList = function() {
if(this.readyList != null)
this.myreadylist = this.readyList.copy();
return this.myreadylist;
};
$(document).ready(function() {
alert("blah");
});
</script>
<script>
// this should be added last so it gets all the ready event
$(document).ready(function() {
readylist = $.getReadyList();
});
</script>
then in the body I have:
<input type="button" onclick="$(readylist).each(function(){this();});" value="trigger ready" />
basically what i did was add a function to jQuery that copies the readyList before it's cleared out, then it will be available to be used by you.
it looks like the code below doesnt work:
function AjaxLoaded() {
$(document).trigger('ready');
}
drop the quotes around document.
Since the jQuery readyList is not exposed as of version 1.4 (discussed here) the nice solutions above are broken.
A way around this is by creating your own readyList, through overriding the original jQuery-ready method. This needs to be done before other scripts that use the original ready method are loaded. Otherwise just the same code as John/Kikito:
// Overrides jQuery-ready and makes it triggerable with $.triggerReady
// This script needs to be included before other scripts using the jQuery-ready.
// Tested with jQuery 1.7
(function(){
var readyList = [];
// Store a reference to the original ready method.
var originalReadyMethod = jQuery.fn.ready;
// Override jQuery.fn.ready
jQuery.fn.ready = function(){
if(arguments.length && arguments.length > 0 && typeof arguments[0] === 'function') {
readyList.push(arguments[0]);
}
// Execute the original method.
originalReadyMethod.apply( this, arguments );
};
// Used to trigger all ready events
$.triggerReady = function() {
$(readyList).each(function(){this();});
};
})();
I'm not sure whether it is advisable to override the ready method. Feel free to advise me on that. I have not yet found any side effects myself though.
Just in case anyone needs it, I refined John's solution a bit so it could be used directly as an included javascript file.
// jquery_trigger_ready.js
// this function is added to jQuery, it allows access to the readylist
// it works for jQuery 1.3.2, it might break on future versions
$.getReadyList = function() {
if(this.readyList != null) { this.myreadylist = [].concat(this.readyList); }
return this.myreadylist;
};
$(document).ready(function() {
readylist = $.getReadyList();
});
$.triggerReady = function() {
$(readylist).each(function(){this();});
}
Including this file after including jquery allows for triggering ready by invoking $.triggerReady(). Example:
<html>
<head>
<title>trigger ready event</title>
<script src="test2_files/jquery-1.js" type="text/javascript"></script>
<script src="jquery_trigger_ready.js" type="text/javascript"></script>
</head>
<body>
<input onclick="$.triggerReady();" value="trigger ready" type="button">
<script type="text/javascript">
$(document).ready(function(){
alert("blah");
});
</script>
</body>
</html>
By the way, I wanted to make it $(document).triggerReady(). If anyone is willing to share some advice on that, ill be appreciated.
We had the same problem and solved it another way.
Instead of
$(document).ready(function () {
$('.specialClass').click(....
We used :
$(document).bind('ready', function(event) {
$('.specialClass', event.target).click(..
jQuery will trigger a "ready" event on the document as usual. When we load the content of a new div via ajax, we can write:
loadedDiv.trigger('ready')
And have all the initialization performed only on the div, obtaining what expected.
Simone Gianni's Answer I think is the most elegant and clean.
and you can even simplify it to become even more easy to use:
jQuery.fn.loadExtended = function(url,completeCallback){
return this.load(url,function(responseText, textStatus, XMLHttpRequest) {
if (completeCallback !== undefined && completeCallback !== null) {
completeCallback(responseText, textStatus, XMLHttpRequest);
}
$(this).trigger("ready");
});
};
So, now instead of using:
$(".container").load(url,function(responseText, textStatus, XMLHttpRequest) {
$(this).trigger("ready");
});
you can just use:
$(".container").loadExtended("tag_cloud.html");
or:
$(".container").loadExtended("tag_cloud.html",function(){
alert('callback function')
});
This has the advantage of only applying the trigger on the div that's being updated.
If your new loaded HTML contain <script> elements and you try insert it into main HTML with pure JS (element.innerHTML = newHTML), then $(document).ready handlers at newHTML and wrapped functions like (function() { /* some functions */ })(); - will not execute because JQuery unbind 'ready' event after first triggering and you can not trigger it repeatly. PS. But you can use $.holdReady(true) and trigger when need.
So, try insert code with jquery method, $(element).html(newHTML). This solved similar problem for me, seems jquery handle js before inserting. Using this method you also will not see the <script> elements among DOM nodes (at browser's Elements Inspector for ex.)

Categories

Resources