I found a little javascript snippet for including javascripts only if they was not included before.
That is working with my own scripts, but with two third-party libraries it's not working and I really don't know why.
var included_files = new Array();
function include_once(script_filename) {
if (!in_array(script_filename, included_files)) {
included_files[included_files.length] = script_filename;
include_dom(script_filename);
}
}
function in_array(needle, haystack) {
for (var i = 0; i < haystack.length; i++) {
if (haystack[i] == needle) {
return true;
}
}
return false;
}
function include_dom(script_filename) {
var html_doc = document.getElementsByTagName('head').item(0);
var js = document.createElement('script');
js.setAttribute('language', 'javascript');
js.setAttribute('type', 'text/javascript');
js.setAttribute('src', script_filename);
html_doc.appendChild(js);
return false;
}
function loaded() {
include_once("shared/scripts/jquery.min.js");
include_once("shared/scripts/iscroll.js");
$(document).ready(function () {
alert("hello");
});
}
error: $ is not defined.
If I import jQuery the regular way its working and it says "iScroll" is not defined (because I'm using it later).
Any ideas?
include_dom is asynchronous. It loads the scripts in parallel, and you can't really determine when the scripts will be loaded. You try to use jQuery right after you started the download, which doesn't work.
You need to use a script that allows you to specify a callback for loaded scripts. I would recommend require.js
You are adding the scripts to the DOM, but not letting them load before you try to use the functions they provide.
You need to bind a callback to the load event of the script elements you are adding.
(At least in most browsers, you might have to implement some hacks in others; you may wish to examine the source code for jQuery's getScript method).
Did someone say callback?
function include_once(script_filename, callback) {
if (!in_array(script_filename, included_files)) {
included_files[included_files.length] = script_filename;
include_dom(script_filename, callback);
}
}
function include_dom(script_filename, callback) {
var html_doc = document.getElementsByTagName('head').item(0);
var js = document.createElement('script');
js.setAttribute('language', 'javascript');
js.setAttribute('type', 'text/javascript');
js.setAttribute('src', script_filename);
if(callback && callback != 'undefined'){
js.onload = callback;
js.onreadystatechange = function() {
if (this.readyState == 'complete') callback();
}
}
html_doc.appendChild(js);
return false;
}
function loaded() {
include_once("shared/scripts/jquery.min.js", function(){
$(document).ready(function () {
alert("hello");
});
});
include_once("shared/scripts/iscroll.js");
}
Use a script loader. yepnope will do everything you are trying to do and more
Related
You might be familiar with the good old Jquery load fallback:
<script>window.jQuery || document.write('<script src="https://example.com/jquery.js"></script>')</script>
But I read here and there: don’t use document.write, is bad for your health, it does not work on Chrome (It’s working for me, Chrome 78).
So I’m trying to replace it, but I’m not able to find a solution that will load synchronously the new js file, before DOM loaded is triggered.
And what ends happening with a DOM manipulation alternative is that the browser consideres the DOM is loaded and all $(document).ready() fail with “$ is not defined”.
function Jqfallback() {
var j = document.createElement('script');
j.src = 'https://example.com/jquery.js';
document.getElementsByTagName('head')[0].appendChild(j);
}
(window.jQuery || Jqfallback() );
No matter where I put this script, or the new JS file, which in this case ('head')[0] is already before all other JS which are in the body, it loads it “asyncronically”.
Is there another option or I continue rocking document.write() in late 2019?
It takes a bit of time to load and parse JQuery. So use a (small) timeout after appending the script.
This snippet wraps conditional loading in a immediately executed anonymous function:
(myScripting => {
if (!window.$) {
let j = document.createElement('script');
j.src = '//code.jquery.com/jquery-3.4.1.slim.min.js';
document.querySelector('head').appendChild(j);
setTimeout( myScripting, 200 );
} else {
myScripting();
}
})(JqIsLoadedSoMyScriptingCanStart);
// put your main scripting in here
function JqIsLoadedSoMyScriptingCanStart() {
// extra check
if (!window.$) {
alert("Sorry, JQuery is not loaded, can't continue");
return;
}
console.log("JQuery in place?");
console.log($("head script")[1]);
}
<script src="cantLoadThis"></script>
Place the code that uses jQuery in the onload() function.
var jQuery1 = document.createElement('script');
jQuery1.src = "https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js";
jQuery1.onload = function () {
var $ = window.jQuery;
$.when(
$.getScript("https://someOtherScript.js"), //if you need
$.Deferred(function (deferred) {
$(deferred.resolve);
})
).done(function () {
console.log("all scripts loaded!!");
doNextTask(); //some other code which uses jQuery
});
};
Append jQuery to your document in onreadystatechange
document.onreadystatechange = function () {
if (document.readyState == "complete") {
// document is ready.
document.head.appendChild(jQuery1);
}
}
I use this in the head tag:
<script src="js/lightbox.js"></script>
Is it possible to remove this off the header and load this file with onload()?
<body onload="...">...</body>
Note: This is not a function, it's an external js file with several functions.
Thanks!
<script>
function loadJS(src, callback) {
var s = document.createElement('script');
s.src = src;
s.async = true;
s.onreadystatechange = s.onload = function() {
var state = s.readyState;
if (!callback.done && (!state || /loaded|complete/.test(state))) {
callback.done = true;
callback();
}
};
document.getElementsByTagName('head')[0].appendChild(s);
}
loadJS('/script/script.js', function() {
// put your code here to run after script is loaded
});
</script>
I still think its better to load in jQuery and use $.getScript instead as you have lots of goodies there.
Can call this on body load
onload="blabla();"
function blabla()
{
$.getScript( 'url to your js file', function( data, textStatus, jqxhr ) {
// do some stuff after script is loaded
});
}
You can learn more here
Source
If you want to do it without jQuery, use this
function addScript(filename)
{
var scriptBlock=document.createElement('script')
scriptBlock.setAttribute("type","text/javascript")
scriptBlock.setAttribute("src", filename)
document.getElementsByTagName("head")[0].appendChild(scriptBlock)
}
and call it with <body onload="addScript('myFile.js')". If you have multiple files to load, you could put in a wrapper, that adds all the files you want.
Use $(document).ready()
and from this function load javascript. It sounds crazy but can be done. please follow http://www.javascriptkit.com/javatutors/loadjavascriptcss.shtml
var JS = {
load: function(src, callback) {
var script = document.createElement('script'),
loaded;
script.setAttribute('src', src);
if (callback) {
script.onreadystatechange = script.onload = function() {
if (!loaded) {
callback();
}
loaded = true;
};
}
document.getElementsByTagName('head')[0].appendChild(script);
}
};
// Example with callback
JS.load("http://www.someawesomedomain.com/some.js", function() {
//Do your thing.
});
I have a array where i have specified the files i need to load in javascript before calling specific script. Lets call those particular lines of code as myscript.
I did as follows
var fileNamesArray = new Array();
fileNamesArray.push("abc.js");
fileNamesArray.push("pqr.js");
fileNamesArray.push("xyz.js");
fileNamesArray.push("klm.js");
var totalFiles = jQuery(fileNamesArray).length;
var tempCount = 0;
jQuery.each(fileNamesArray, function(key, value) {
jQuery.getScript(value, function() {
tempCount++;
});
});
to check whether all files are being loaded or not, i done following thing but doesn't seems to be effective
var refreshIntervalId = setInterval(function() {
if (tempCount == totalFiles) {
clearInterval(refreshIntervalId);
return;
}
}, 10);
i have implemented these in object oriented javascript as follows
function Loader() {
this.jQuery = null;
// check for specifically jQuery 1.8.2+, if not, load it
if (jQuery == undefined) {
jQuery.getScript(
"/Common/javascript/jquery/map/javascript/jquery-1.8.2.js",
function() {
this.jQuery = jQuery.noConflict();
});
} else {
var jQueryVersion = $.fn.jquery;
jQueryVersion = parseInt(jQueryVersion.split('.').join(""));
if (182 > jQueryVersion) {
jQuery.getScript(
"/Common/javascript/jquery/map/javascript/jquery-1.8.2.js",
function() {
this.jQuery = jQuery.noConflict();
});
}
}
}
Loader.prototype.LoadAllFile = function() {
//here i am loading all files
}
Loader.prototype.bindMap = function(options) {
this.LoadAllFile();
//execute the script after loading the files... which we called as myscript
}
i am loading more than 12-14 js files via ajax.
if you observe Loader.prototype.bindMap, i am loading all the files first and then executing the script.
But it seems that myscript the script start executing before all files being loaded.
what are the better ways to execute the script only after all js files are loaded.
Take a look at jQuery's .load() http://api.jquery.com/load-event/
$('script').load(function () { });
Based on the documentation on Jquery.getScript , it is a shorthand for Jquery.ajax. By default this in async call. You might want to change it to do a synchronous call.
To set this property, you can refer to this
So instead of doing a setInterval, you can just loop in your array and do a Jquery.getScript.
The following works but I need to distribute it to clients that may be uncomfortable of pasting all this script into their home page. Just wondering if it can be simplified? I need to load Jquery 1.71, then the UI and then my own script and then call the function in my own script. Even minimized its rather long.
Hope some javascript guru can help. Thanks!
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js';
script.type = 'text/javascript';
head.appendChild(script);
if (script.onreadystatechange) script.onreadystatechange = function () {
if (script.readyState == "complete" || script.readyState == "loaded") {
script.onreadystatechange = false;
//alert("complete");
load_script();
}
} else {
script.onload = function () {
//alert("complete");
load_script();
}
}
//setup array of scripts and an index to keep track of where we are in the process
var scripts = ['script/jquery-ui-1.8.7.custom.min.js', 'script/wfo171.js'],
index = 0;
//setup a function that loads a single script
function load_script() {
//make sure the current index is still a part of the array
if (index < scripts.length) {
//get the script at the current index
$.getScript('http://mydomainn.com/script/' + scripts[index], function () {
//once the script is loaded, increase the index and attempt to load the next script
//alert('Loaded: ' + scripts[index] + "," + index);
if (index != 0) {
LoadEdge();
}
index++;
load_script();
});
}
}
function LoadEdge() {
Edge('f08430fa2a');
}
As soon as you have jQuery you can use its power:
$.when.apply($, $.map(scripts, $.getScript)).then(LoadEdge);
This relies on its deferred functionality - each URL is replaced with a getScript deferred (this will fetch the script), and these deferreds are then passed to $.when so that you can add a callback using .then to be called when all scripts have finished loaded.
Why don;t you just use an onload event to make sure everything is loaded before trying to execute?
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="http://mydomainn.com/script/jquery-ui-1.8.7.custom.min.js"></script>
<script src="http://mydomainn.com/script/wfo171.js"></script>
<script>
$(function() { // this executes when the page is ready
Edge('f08430fa2a');
});
</script>
(check the paths on the scripts, you seem to be loading from /script/script, wasn't sure if that was correct so I removed it.
I've got a bookmarklet which loads jQuery and some other js libraries.
How do I:
Wait until the javascript library I'm using is available/loaded. If I try to use the script before it has finished loading, like using the $ function with jQuery before it's loaded, an undefined exception is thrown.
Insure that the bookmarklet I load won't be cached (without using a server header, or obviously, being that this is a javascript file: a metatag)
Is anyone aware if onload for dynamically added javascript works in IE? (to contradict this post)
What's the simplest solution, cleanest resolution to these issues?
It depends on how you are actually loading jQuery. If you are appending a script element to the page, you can use the same technique that jQuery uses to dynamically load a script.
EDIT: I did my homework and actually extracted a loadScript function from the jQuery code to use in your bookmarklet. It might actually be useful to many (including me).
function loadScript(url, callback)
{
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.src = url;
// Attach handlers for all browsers
var done = false;
script.onload = script.onreadystatechange = function()
{
if( !done && ( !this.readyState
|| this.readyState == "loaded"
|| this.readyState == "complete") )
{
done = true;
// Continue your code
callback();
// Handle memory leak in IE
script.onload = script.onreadystatechange = null;
head.removeChild( script );
}
};
head.appendChild(script);
}
// Usage:
// This code loads jQuery and executes some code when jQuery is loaded
loadScript("https://code.jquery.com/jquery-latest.js", function()
{
$('my_element').hide();
});
To answer your first question: Javascript is interpreted sequentially, so any following bookmarklet code will not execute until the library is loaded (assuming the library was interpreted successfully - no syntax errors).
To prevent the files from being cached, you can append a meaningless query string...
url = 'jquery.js?x=' + new Date().getTime();
I've paid an attention that in Chrome the order of scripts that are loaded is undetermined, when using #Vincent Robert's technique. In this case a little modification helps:
(function() {
var callback = function() {
// Do you work
};
// check for our library existence
if (typeof (MyLib) == 'undefined') {
var sources = [
'http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js',
'https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js',
'https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js',
'http://myhost.com/javascripts/mylib.min.js'];
var loadNextScript = function() {
if (sources.length > 0) {
var script = document.createElement('script');
script.src = sources.shift();
document.body.appendChild(script);
var done = false;
script.onload = script.onreadystatechange = function() {
if (!done
&& (!this.readyState || this.readyState == "loaded" || this.readyState == "complete")) {
done = true;
// Handle memory leak in IE
script.onload = script.onreadystatechange = null;
loadNextScript();
}
}
} else {
callback();
}
}
loadNextScript();
} else {
callback();
}
})();
I got a little closer with this, but not completely. It would be nice to have a discrete, example of a bookmarklet that demonstrated how to avoided caching.