I try to write a JavaScript function that loads a js script (src) and performs some callback when the script is loaded.
I also look if a script with the same src already exists.
My problem is that if the script already loaded, the callback will not be performed. That is NOK.
How to know if the script was already loaded?
importScript: (function (head) {
function loadError(error) {
throw new URIError("The script " +
error.target.src + " is not accessible.");}
return function (url, callback) {
var existingScript = document.querySelectorAll("script[src='" +
url + "']");
var isNewScript = (existingScript.length == 0);
var script;
if (isNewScript) {
script = document.createElement("script")
script.type = "text/javascript";
}
else {
script = existingScript[0];
}
script.onerror = loadError;
if (script.readyState) { //IE
script.onreadystatechange = function () {
if (script.readyState == "loaded" ||
script.readyState == "complete") {
script.onreadystatechange = null;
if (callback) {
callback(); }
}
};
} else { // others than IE
script.onload = callback; }
if (isNewScript) {
script.src = url;
head.appendChild(script); }
}
})(document.head || document.getElementsByTagName("head")[0])
As I understand, the script.readyState == "loaded" || script.readyState == "complete" could work only for IE, not for other browsers as well...
Usage:
importScript("myScript1.js");
importScript("myScript2.js", /* onload function: */
function () { alert("The script has been OK loaded."); });
I recommend jQuery, it's so easy with that. Life is too short for coding things like that yourself (you will waste hours for supporting all browsers).
$.ajax({
url: "/script.js",
dataType: "script",
success: function() {
console.log("script loaded");
}
});
EDIT:
It's even easier (example from jQuery docs):
$.getScript( "ajax/test.js", function( data, textStatus, jqxhr ) {
console.log(data); // Data returned
console.log(textStatus); // Success
console.log(jqxhr.status); // 200
});
You can also chain done and fail to have additional callbacks:
$.getScript("ajax/test.js")
.done(function(script, textStatus) {
console.log(textStatus);
})
.fail(function(jqxhr, settings, exception) {
console.log("loading script failed.");
});
Load jQuery asynchronously
<script src="path/to/jquery"></script>
<script>
function wait(method) {
if (window.$) {
method();
} else {
setTimeout(function () { wait(method); }, 100); // check every 100ms
}
}
// wait for jQuery
wait(function() {
// jQuery has loaded!
$("#foo").doSomething();
// you can now load other scripts with jQuery:
$.getScript("ajax/test.js")
.done(function(script, textStatus) {
console.log(textStatus);
})
.fail(function(jqxhr, settings, exception) {
console.log("loading script failed.");
});
}
</script>
Well the safest way to check if script is loaded is you can add a simple callback at end of script . Which if exist can be called with some data also to be passed.
if(window.loaded){
window.loaded(params);
}
Once the script loads it will execute this method which you can declare in your parent script which will be called.
Also you can trigger an event on body and listen on that event in other parent code.
Based on method from Luca Steeb, I refine the solution to just two script tags, for SPA applications, index.html is very compact with:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Simplified INDEX</title>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="/bootloader.js"></script>
</head>
<body>
</body>
</html>
bootloader.js, combine ideas from Luca and load css using jquery :
function loadScripts() {
// jQuery has loaded!
console.log("jquery is loaded");
// you can now load other scripts and css files with jQuery:
$.when($.getStylesheet('css/main.css'), $.getScript('js/main.js'))
.then(function () {
console.log('the css and js loaded successfully and are both ready');
}, function () {
console.log('an error occurred somewhere');
});
}
function patchGetStylesheet($) {
$.getStylesheet = function (href) {
var $d = $.Deferred();
var $link = $('<link/>', {
rel: 'stylesheet',
type: 'text/css',
href: href
}).appendTo('head');
$d.resolve($link);
return $d.promise();
};
}
function wait(method) {
if (window.$) {
patchGetStylesheet(window.$);
method();
} else {
setTimeout(function () {
wait(method);
}, 100); // check every 100ms
}
}
// wait for jQuery
wait(loadScripts);
For bootloader.js, it could be minified、obfused.... using webpack, ...
We will not add code to index.html any more through solving runtime dependency using jquery.
Related
I need to include jQuery in js file since it would be loaded as a external script.
Here is my code:
function addjQuery() {
if (!window.jQuery) {
var jq = document.createElement("script");
jq.type = "text/javascript";
jq.src = "https://code.jquery.com/jquery-3.2.1.min.js";
document.getElementsByTagName("head")[0].appendChild(jq);
console.log("Added jQuery!");
} else {
console.log("jQuery already exists.")
}
}
addjQuery();
jQuery(function($) {
$(document).ready(function() {
});
});
But error occurs:
Uncaught ReferenceError: jQuery is not defined
Even when I run "jQuery" or "$" on console of chrome dev tool, it's working.
What's the problem?
The jQuery() function is firing prior to jQuery being loaded from the script tag - you can add an onload event handler to fire it when the script is done downloading:
function addjQuery() {
if (!window.jQuery) {
var jq = document.createElement("script");
jq.type = "text/javascript";
jq.src = "https://code.jquery.com/jquery-3.2.1.min.js";
document.getElementsByTagName("head")[0].appendChild(jq);
jq.onload = initjQuery;
console.log("jQuery is loaded!");
} else {
console.log("jQuery already exists.")
}
}
function initjQuery () {
jQuery(function($) {
$(document).ready(function() { });
});
}
addjQuery();
I am using Google API, based on their link I have to put the following script in the HTML file
<script src="https://apis.google.com/js/client.js?onload=callback"></script>
The custom callback function is being loaded after the client.js is loaded successfully.
function callback() {
var ROOT = 'https://your_app_id.appspot.com/_ah/api';
gapi.client.load('your_api_name', 'v1', function() {
doSomethingAfterLoading();
}, ROOT);
}
I would like to
Separate HTML with JS file
I downloaded the client.js file and put it in my local repo. But for reducing web request I would like to concat the client.js with other JS file. But I have no idea how to load the content with the concatenated JS file with the callback is being called
Thanks in advance
If you are looking for javascript only solution:
var sScriptSrc = "https://apis.google.com/js/client.js?onload=callback"
loadScript(sScriptSrc);
function loadScript(sScriptSrc) {
var oHead = document.getElementsByTagName("HEAD")[0];
var oScript = document.createElement('script');
oScript.type = 'text/javascript';
oScript.src = sScriptSrc;
oHead.appendChild(oScript);
oScript.onload = loadedCallback();
}
function loadedCallback() {
alert("WoHooo I am loaded");
}
See it running here: JSFiddle
EDIT
Let me do some refining, if I understand correctly what you want to achieve:
I made a simple main html page:
<html>
<head>
<script src="client.js"></script>
</head>
<body>
PAGE BODY
</body>
</html>
Which is loading client.js
client.js contains:
// you can call this function with
// param1: src of the script to load
// param2: function name to be executed once the load is finished
function loadScript(sScriptSrc, loadedCallback) {
var oHead = document.getElementsByTagName("HEAD")[0];
var oScript = document.createElement('script');
oScript.type = 'text/javascript';
oScript.src = sScriptSrc;
oHead.appendChild(oScript);
oScript.onload = loadedCallback;
}
// let's load the Google API js and run function GoggleApiLoaded once it is done.
loadScript("https://apis.google.com/js/client.js", GoggleApiLoaded);
function GoggleApiLoaded() {
alert("WoHooo Google API js loaded");
}
Of course, instead of GoggleApiLoaded example function you could run a method which start the loading of different js and the callback of that one could load a next one and so on...
Is this what you were looking for?
jQuery has a nice method for this. https://api.jquery.com/jquery.getscript/
jQuery.getScript("https://apis.google.com/js/client.js", function() {
console.log("hello");
})
If you want to be compatible with IE, including IE 9, you can use this async JS file loader & callback:
function loadAsync(src, callback){
var script = document.createElement('script');
script.src = src;
script.type = 'text/javascript';
script.async = true;
if(callback != null){
if (script.readyState) { // IE, incl. IE9
script.onreadystatechange = function() {
if (script.readyState == "loaded" || script.readyState == "complete") {
script.onreadystatechange = null;
callback();
}
};
} else {
script.onload = function() { // Other browsers
callback();
};
}
}
a=document.getElementsByTagName('script')[0];
a.parentNode.insertBefore(script,a);
}
loadAsync("https://www.example.com/script.js", callbackFunction);
function callbackFunction() {
console.log('Callback function run');
}
My script will be using as widget in third-party website so i don't aware about jquery loaded and which version of jquery loaded or not at third-party end.
So Before loading below script i want to check is there already latest jquery 1.11.1 loaded after dom ready if not then i want to load the jquery latest and run below script.
script.js
var $ = jQuery.noConflict( true );
(function( $ ) {
$(document).ready(function() {
alert("Document Ready ");
});
})($jy);
EDIT 1
var addNewJQuery = function() {
(function( $ ) {
$jy = $;
var invokeOriginalScript;
$(document).ready(function() {
......my code here.....
}):
})(jQuery);
}
Not sure if this is working for you, but it looks like it is working.
Maybe you need to remove the other script from your header after you loaded the second jQuery file. But it seems to work with both scripts loaded.
I've also added a check if jQuery is loaded at all, if not it will load jQuery.
You can also find the same code in this fiddle.
var addNewJQuery = function() {
//var jQ = jQuery.noConflict(true);
(function ($) {
$(document).ready(function () {
alert("You are now running jQuery version: " + $.fn.jquery);
});
})(jQuery);
};
if ( typeof jQuery === 'undefined' ) {
alert('no jQuery loaded');
//throw new Error("Something went badly wrong!"); // now you could load jQuery
loadScript('https://code.jquery.com/jquery-1.11.2.js', addNewJQuery);
}
if ($.fn.jquery !== '1.11.2') {
console.log('detected other jQuery version: ', $.fn.jquery);
loadScript('https://code.jquery.com/jquery-1.11.2.js', addNewJQuery);
}
function loadScript(url, callback)
{
// Adding the script tag to the head as suggested before
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
// Then bind the event to the callback function.
// There are several events for cross browser compatibility.
script.onreadystatechange = callback;
script.onload = callback;
// Fire the loading
head.appendChild(script);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
I'm trying to handle JQuery not loading.
(this is for a javascript api, frequently the developer consuming it forgets to include jquery, hence I want to instruct them on what is missing)
I have a bunch of code in various files that runs on document.ready
e.g.
(function ($, undefined) {
//stuff
})( jQuery );
If JQuery is not loaded then the code above breaks.
A workaround I've found is to add a check for Jquery instead through a function
e.g.
(function ($, undefined) {
//stuff
})( JQueryCheck() );
function JQueryCheck() {
if (window.jQuery == undefined)
alert("no jquery");
else
return jQuery;
}
I'm not sure if this is strong enough, if theres a better way to do it then let me know.
On top of this I want prevent the other document.readys from running, theres no point as all depend on JQuery being loaded.
This must be common issue but I'm struggling to find a solution.
Don't load script files like this <script src="some-path"></script> in Html
instead do this:
if(window.jQuery){
$.getScript('path to js file');
}
This checks for jquery and if it exists, it loads the script and executes it.
Try this:
function JQueryCheck() {
return !!jQuery;
}
Or:
function JQueryCheck() {
try{
jQuery();
} catch(e){
if(e){
return false;
} else {
return true;
}
}
}
Or:
function JQueryCheck() {
if(window.jQuery){
return true;
}else{
return false;
}
}
Good luck!
Your code should work fine, but you could simplify it a bit:
(function ($, undefined) {
if(!$) {
return alert("no jquery");
}
//stuff
})(window.jQuery);
You could also just load it when it's not loaded already:
(function (undefined) {
if(!window.jQuery) {
var script = document.createElement("SCRIPT");
script.src = 'http://code.jquery.com/jquery-2.1.0.min.js';
script.type = 'text/javascript';
document.getElementsByTagName("head")[0].appendChild(script);
// Poll for jQuery to come into existance
var checkReady = function(callback) {
if (window.jQuery) {
callback();
}
else {
window.setTimeout(function() { checkReady(callback); }, 100);
}
};
// Start polling...
checkReady(main);
} else {
main();
}
}());
function main() {
alert("jquery loaded");
};
Taken from https://stackoverflow.com/a/10113434/941764
Whilst it would be best to solve the issues you are having with it not loading this will do what you want it to:
if(window.jQuery) {
//jQuery Code
}
Alternatively if you're after loading a local file if a hosted one has failed, this would work:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery.min.js"><\/script>')</script>
I have a TextBox and a Button:
If the value inside the Textbox is 1 (just emulating a condition)) I need to load jQuery on the fly and use a document Ready function :
I tried this :
function work() //when button click
{
if (document.getElementById('tb').value == '1')
{
if (typeof jQuery == 'undefined')
{
var script = document.createElement('script');
script.src = "http://code.jquery.com/jquery-git2.js";
document.getElementsByTagName('head')[0].appendChild(script);
$(document).ready(function ()
{
alert('');
});
}
}
}
But it says :
Uncaught ReferenceError: $ is not defined
I assume it's because the line : $(document).ready(function ()....
But I don't understand why there is a problem , since i'm, loading jQuery BEFORE I use $...
Question :
How can I fix my code to work as desired ?
JSBIN
You are missing the script onload handler:
var script = document.createElement('script');
// do something with script
// onload handler
script.onload = function () {
// script was loaded, you can use it!
};
Your function becomes:
function work() {
if (document.getElementById('tb').value != '1') { return; }
if (typeof jQuery != 'undefined') { return; }
// jQuery is undefined, we will load it
var script = document.createElement('script');
script.src = "http://code.jquery.com/jquery-git2.js";
document.getElementsByTagName('head')[0].appendChild(script);
// load handler
script.onload = function () {
// jQuery was just loaded!
$(document).ready(function () {
alert('');
});
};
}
Also, do not forget script.onreadystatechange for IE compatibility.
script.onreadystatechange = function () {
if (script.readyState === 'loaded' || script.readyState === 'complete') {
// script was loaded
}
}
Also seems that YepNope would be a good option, too.
JSBIN DEMO
Using YepNope would probably a good option in this case.
yepnope([
{
test: window.jQuery,
nope: 'path/url-to-jquery.js',
complete: function() {
$(document).ready(function() {
//whatever you need jquery for
});
}
}
]);
You can just put that in the head of your document, and it will only load jquery if window.jQuery isn't defined. It's much more reliable (and simpler) than script.onload or script.onreadystatechange. the callback complete will only be called once jquery is loaded, so you can be sure that $ will be defined at that point.
Note: if you're using Modernizr.js on your site, there's a good chance yepnope is already bundled into that script.