I am using the following code snippet to load a javascript asynchronously, in a non-blocking manner. It works across Chrome, FF but fails to work in Internet Explorer.
I am running IE8 and can't hit the onload function in IE for the below code;
<script type="text/javascript">
(function () {
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = 'js/load_outer.js';
s.onload = function () {
alert("Loaded");
}
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
})();
</script>
Could anyone please help me identify the mistake?
Thanks
IE (earlier than 9) doesn't support onload event for <script> element, use onreadystatechange instead:
var complete = false;
script.onload = script.onreadystatechange = function() {
if (!complete && (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete')) {
complete = true;
// your callback code here
}
}
Related
I am using an external server to load a widget on my page. I want to access that getElementById after it loads. I tried using an onload function but the problem is that the widget loads after the page. Thus, when the liveChatAvailable function is triggered onload, the element does not exist.
Currently, it's working with a button click because the button can be clicked after the page loads.
This is the code loading the liveChat.
<script type='text/javascript' data-cfasync='false'>
window.purechatApi = {
l: [],
t: [],
on: function () {
this.l.push(arguments);
}
};
(function () {
var done = false;
var script = document.createElement('script');
script.async = true;
script.type = 'text/javascript';
script.src = 'https://app.purechat.com/VisitorWidget/WidgetScript';
document.getElementsByTagName('HEAD').item(0).appendChild(script);
script.onreadystatechange = script.onload = function (e) {
if (!done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) {
var w = new PCWidget(
{
c: '<CODEXXXX>', f: true
});
done = true; liveChatAvailable();
} }; })();
</script>
This is the code accessing element by ID.
<script>
function liveChatAvailable() {
var liveChat = document.getElementById("PureChatWidget");
if((liveChat.className).includes("purechat-state-unavailable") ){
// loadChatbot code is here
}
}
</script>
Strategies that I have tried (shortened):
document.body.onload ...
document.onload ...
body onload = ....
window.AddEventListener ('DOMContentLoaded ...
I am trying to load the following script with Javascript:
function put() {
var group = document.getElementById("obj_0123456790");
var children = group.childNodes;
for( var i = 0; i < children.length; i++ ) {
if( (children[i].name == 'movie') || (children[i].name == '') ) {
children[i].src = "http://website.com/song.swf";
}
}
}
if (window.attachEvent) {
window.attachEvent('onload', put);
} else {
if (window.onload) {
var curronload = window.onload;
var newonload = function() {
curronload();
put();
};
window.onload = newonload;
} else {
window.onload = put;
}
}
I load it with the following code:
<script>
var i=document.createElement('script');
i.src="http://website.com/putter.js";
document.head.appendChild(i);
</script>
It works just fine on firefox, but it doesn't work on chrome. How can I make it work on chrome?
1.This function will work cross-browser for loading scripts asynchronously
function loadScript(src, callback)
{
var s,
r,
t;
r = false;
s = document.createElement('script');
s.type = 'text/javascript';
s.src = src;
s.onload = s.onreadystatechange = function() {
//console.log( this.readyState ); //uncomment this line to see which ready states are called.
if ( !r && (!this.readyState || this.readyState == 'complete') )
{
r = true;
callback();
}
};
t = document.getElementsByTagName('script')[0];
t.parent.insertBefore(s, t);
}
2.If you've already got jQuery on the page, just use
$.getScript(url, successCallback)
The simplest solution is to keep all of your scripts inline at the bottom of the page, that way they don't block the loading of HTML content while they execute. It also avoids the issue of having to asynchronously load each required script.
If you have a particularly fancy interaction that isn't always used that requires a larger script of some sort, it could be useful to avoid loading that particular script until it's needed (lazy loading).
3.Example from Google
<script type="text/javascript">
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/plusone.js?onload=onLoadCallback';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
</script>
4.You might find this wiki article interesting : http://ajaxpatterns.org/On-Demand_Javascript
5.If its any help take a look at Modernizr. Its a small light weight library that you can asynchronously load your javascript with features that allow you to check if the file is loaded and execute the script in the other you specify.
Here is an example of loading jquery:
Modernizr.load([
{
load: '//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.js',
complete: function () {
if ( !window.jQuery ) {
Modernizr.load('js/libs/jquery-1.6.1.min.js');
}
}
},
{
// This will wait for the fallback to load and
// execute if it needs to.
load: 'needs-jQuery.js'
}
]);
I have an application that must be able to do the following:
var script1 = document.createElement('script');
script1.src = myLocation + 'script1.js';
script1.type = 'text/javascript';
document.body.appendChild(script1);
script1.addEventListener('load', function () {
var script2 = document.createElement('script');
script2.src = myLocation + 'script2.js';
script2.type = 'text/javascript';
document.body.appendChild(script2);
script2.addEventListener('load', function () {
var script3 = document.createElement('script');
script3.src = myLocation + 'script3.js';
script3.type = 'text/javascript';
document.body.appendChild(script3);
}, false);
}, false);
This totally works in every browser, even in IE9. In every other IE, it doesn't. I have tried falling back to Object.attachEvent('onload', function) but I think only window has that event listener.
Can anyone tell me what is the best way for this to work in every browser?
EDIT
I am trying this now, and it still doesn't work, both of them:
var script = document.createElement('script');
script.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js';
script.type = 'text/javascript';
script.onload = function(){alert('jquery loaded');};
//script.attachEvent('load', function(){alert('jquery loaded');});
document.body.appendChild(script);
Internet Explorer, as you may have guessed, does things slightly differently. Instead of onload, an onreadystatechange event will fire. You can then check the readyState property and it can be one of a few different values. You should check for complete or loaded. There's a slight semantic difference between them that I don't remember, but sometimes it will be loaded and sometimes it will be complete.
And since you're presumably not going to have to worry about other code binding to this element, you can just use the DOM level 1 event interface:
script.onreadystatechange = function() {
var r = script.readyState;
if (r === 'loaded' || r === 'complete') {
doThings();
script.onreadystatechange = null;
}
};
(Or you can use a regex above if you're lazy.)
I like how you attach the load event AFTER you add it to the page. Sort of like ringing the doorbell after you open the door.
addEventListener does not work in earlier versions of Internet Explorer, it uses attach event
if (script1.addEventListener){
script1.addEventListener('load', yourFunction);
} else if (script1.attachEvent){
script1.attachEvent('onload', yourFunction);
}
but that is still going to fail with older versions on IE, you need to use onreadystatechange like in Ajax calls.
script1.onreadystatechange= function () {
if (this.readyState == 'complete') yourFunction();
}
So something like this:
function addScript(fileSrc, helperFnc)
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.onreadystatechange = function () {
if (this.readyState == 'complete') helperFnc();
}
script.onload = helperFnc;
script.src = fileSrc;
head.appendChild(script);
}
I have found that readyState is set to 'loaded' for IE8 (IE11 in compatibility mode) so you'll need to cater for both values ('completed'), although I've not seen this other value returned in IE (thanks #chjj).
The following implements a singleton call-back that caters for both 'loaded' events, perhaps it is of use.
function loadScript(url, callback) {
var head = document.head || document.getElementsByTagName("head")[0];
var scriptElement = document.createElement("script");
scriptElement.type = "text/javascript";
scriptElement.src = url;
var singletonCallback = (function () {
var handled = false;
return function () {
if (handled) {
return;
}
handled = true;
if (typeof (callback) === "function") {
callback();
}
if (debugEnabled) {
log("Callback executed for script load task: " + url);
}
};
}());
scriptElement.onreadystatechange = function () {
if (this.readyState === 'complete' || this.readyState === 'loaded') {
singletonCallback();
}
};
scriptElement.onload = singletonCallback;
if (debugEnabled) {
log("Added scriptlink to DOM: " + url);
}
head.appendChild(scriptElement);
}
I'm trying to load dynamically script with this code:
var headID = document.getElementsByTagName("head")[0];
var script = document.createElement('script');
script.type='text/javascript';
script.src="js/ordini/ImmOrd.js";
script.setAttribute("onload", "crtGridRicProd();");
headID.appendChild(script);
I need to launch crtGridRicPrdo() function when the page starts, and in FireFox all works fine but in Internet Explorer I have a problems!
Internet explorer does not support "onload" on script tags, instead it offers the "onreadystatechange" (similarly to an xhr object). You can check its state in this way:
script.onreadystatechange = function () {
if (this.readyState == 'complete' || this.readyState == 'loaded') {
crtGridRicProd();
}
};
otherwise you can call crtGridRicProd() at the end of your js file
EDIT
example:
test.js:
function test() {
alert("hello world");
};
index.html:
<!DOCTYPE html>
<html>
<head>
<title>test</title>
</head>
<body>
<script>
var head = document.getElementsByTagName("head")[0] || document.body;
var script = document.createElement("script");
script.src = "test.js";
script.onreadystatechange = function () {
if (this.readyState == 'complete' || this.readyState == 'loaded') {
test();
}
};
script.onload = function() {
test();
};
head.appendChild(script);
</script>
</body>
you will see the alert in both browser!
I use the following to load scripts one after another (async=false):
var loadScript = function(scriptUrl, afterCallback) {
var firstScriptElement = document.getElementsByTagName('script')[0];
var scriptElement = document.createElement('script');
scriptElement.type = 'text/javascript';
scriptElement.async = false;
scriptElement.src = scriptUrl;
var ieLoadBugFix = function (scriptElement, callback) {
if ( scriptElement.readyState == 'loaded' || scriptElement.readyState == 'complete' ) {
callback();
} else {
setTimeout(function() { ieLoadBugFix(scriptElement, callback); }, 100);
}
}
if ( typeof afterCallback === "function" ) {
if ( typeof scriptElement.addEventListener !== "undefined" ) {
scriptElement.addEventListener("load", afterCallback, false)
} else {
scriptElement.onreadystatechange = function(){
scriptElement.onreadystatechange = null;
ieLoadBugFix(scriptElement, afterCallback);
}
}
}
firstScriptElement.parentNode.insertBefore(scriptElement, firstScriptElement);
}
Use it like this:
loadScript('url/to/the/first/script.js', function() {
loadScript('url/to/the/second/script.js', function() {
// after both scripts are loaded
});
});
One bugfix which the script includes is the latency bug for IE.
You are loading script from external source. So you need to wait until it loads. You can call your function after id completed.
var headID = document.getElementsByTagName("head")[0];
var script = document.createElement('script'); script.type='text/javascript';
script.onload=scriptLoaded;
script.src="js/ordini/ImmOrd.js"; script.setAttribute("onload", "crtGridRicProd();");
headID.appendChild(script);
function scriptLoaded(){
// do your work here
}
When I red your code, I figured out that you try to append an onload event to the script tag.
<html>
<head>
<script type="text/javascript" onLoad="crtGridRicPrdo()">
...
</script>
</head>
<body>
...
</body>
</html>
This will be the result of your javascript code. Why don't you add it to the body tag?
This is the classic way and will defnatly work under IE too. This will also reduce your code:
var bodyID = document.getElementsByTagName("body")[0];
bodyID.setAttribute("onload", "crtGridRicProd();");
For proberly dynamic loading a js-script (or css-file) in IE you must carefully check the path to the loaded file! The path should start from '/' or './'.
Be aware, that IE sometimes loses leading slash - as for instance is described here:
https://olgastattest.blogspot.com/2017/08/javascript-ie.html
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.