Adding events to detect when all dynamically added scripts are loaded - javascript

There are no errors thrown in the code, so I can only assume either the events aren't getting triggered or they aren't getting added properly. Can anyone determine what the issue is here?
Code below. Fiddle here.
$('#fake-body').append('init<br />');
var scriptTag,
scriptsLoaded = 0,
scripts = ['//netdna.bootstrapcdn.com/bootstrap/3.0.2/js/bootstrap.min.js', '//codeorigin.jquery.com/ui/1.9.2/jquery-ui.min.js'],
scriptLoadedCallback = function(val) {
scriptsLoaded++;
$('#fake-body').append('callback called for '+val+' | scriptsloaded = '+scriptsloaded+' & length = '+scripts.length+'<br />');
if(scriptsLoaded === scripts.length) {
$('#fake-body').append('all loaded');
}
};
$.each(scripts, function(index, value) {
$('#fake-body').append('preparing '+value+'<br />');
scriptTag = document.createElement('script');
scriptTag.type = 'text/javascript';
scriptTag.src = value;
if(typeof scriptTag.addEventListener !== 'undefined') {
$('#fake-body').append('add event for good browsers<br />');
scriptTag.addEventListener('load', (function() {
scriptLoadedCallback(value);
}), false);
} else {
$('#fake-body').append('add event for the other one<br />');
scriptTag.attachEvent('onreadystatechange', function() {
if(scriptTag.readyState === 'loaded') {
scriptLoadedCallback(value);
}
});
}
$('#fake-body').append('appending script<br />');
$('#fake-body').append(scriptTag);
});
$('#fake-body').append('complete');

use plain Javascript to load javascript files rather than jquery(because jquery won't fire the load callback in your current code), so replace :
$('#fake-body').append(scriptTag);
with:
$('#fake-body')[0].appendChild(scriptTag);
or if you insist to use jquery, you have to respect the following statements order (or use getScript):
$body.append(scriptTag);
scriptTag.attachEvent
scriptTag.src = scriptUrl;
jsfiddle
you have another error by referencing scriptsloaded rather than scriptsLoaded in the callback.

Related

Including javascripts not working

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

How to include jQuery in an external .js file?

I want to provide my clients a simple code to insert and get my plugin.
The code:
<div id='banner-lujanventas'></div>
<script src="http://lujanventas.com/plugins/banners/script.js" type="text/javascript"></script>
The problem is that my plugin only works with jQuery. How do I check if a version of jQuery is installed on my script.js file and if not include it? (I can only modify my /script.js file)
Make your own script element :
if (typeof jQuery === "undefined") {
var script = document.createElement('script');
script.src = 'http://code.jquery.com/jquery-latest.min.js';
script.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(script);
}
//edit
window.onload = function() {
$(function(){ alert("jQuery + DOM loaded."); });
}
You must put your real onload code in a window.onload() function, and NOT in a $(document).ready() function, because jquery.js is not necessary loaded at this time.
You can check for the jQuery variable
if (typeof jQuery === 'undefined') {
// download it
}
For downloading options, e.g. asynchronous vs. document.write, check out this article.
Something like this:
<script>!window.jQuery && document.write(unescape('%3Cscript src="http://yourdomain.com/js/jquery-1.6.2.min.js"%3E%3C/script%3E'))</script>
I dug up some old code that looks for a particular version of jQuery and loads it if it's not found plus it avoids conflicting with any existing jQuery the page already uses:
// This handles loading the correct version of jQuery without
// interfering with any other version loaded from the parent page.
(function(window, document, version, callback) {
var j, d;
var loaded = false;
if (!(j = window.jQuery) || version > j.fn.jquery || callback(j, loaded)) {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "http://code.jquery.com/jquery-2.1.0.min.js";
script.onload = script.onreadystatechange = function() {
if (!loaded && (!(d = this.readyState) || d == "loaded" || d == "complete")) {
callback((j = window.jQuery).noConflict(1), loaded = true);
j(script).remove();
}
};
(document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script);
}
})(window, document, "2.1", function($) {
$(document).ready(function() {
console.log("Using jQuery version: " + $.fn.jquery);
// Your code goes here...
});
});

Can this be simplified to load multiple scripts in order

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.

how can i load <script>'s into an iframe?

I've got the logic working to append into my iframe from the parent
this works:
$('#iframe').load(function() {
$(this).contents().find('#target').append('this text has been inserted into the iframe by jquery');
});
this doesn't
$('#iframe').load(function() {
$(this).contents().find('body').append('<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>');
});
.lf
The problem is something to do with the inserted script tags not being escaped properly.
Half of the javascript is becomes visible in the html, like the first script tag has been abruptly ended.
Maybe the error is with your string, never create a string in javascript with a literal < /script> in it.
$('#iframe').load(function() {
$(this).contents().find('body').append('<scr' + 'ipt type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></scr' + 'ipt>');
});
I'm a bit surprised that isn't working [Edit: No longer surprised at all, see mtrovo's answer.]...but here's what I do, which is mostly non-jQuery per your comment below but still quite brief:
var rawframe = document.getElementById('theframe');
var framedoc = rawframe.contentDocument;
if (!framedoc && rawframe.contentWindow) {
framedoc = rawframe.contentWindow.document;
}
var script = doc.createElement('script');
script.type = "text/javascript";
script.src = "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js";
framedoc.body.appendChild(script);
Off-topic: I really wouldn't give an iframe (or anything else) the ID "iframe". That just feels like it's asking for trouble (IE has namespace issues, and while I'm not aware of it confusing tag names and IDs, I wouldn't be completely shocked). I've used "theframe" above instead.
Warning: loading script in this manner would make scripts running in main window context
i.e.: if you use window from somescript.js, it would be NOT iframe's window!
$('#iframe').load(function() {
$(this).contents().find('body').append('<scr' + 'ipt type="text/javascript" src="somescript.js"></scr' + 'ipt>');
});
To be able to use iframe context inject script with this:
function insertScript(doc, target, src, callback) {
var s = doc.createElement("script");
s.type = "text/javascript";
if(callback) {
if (s.readyState){ //IE
s.onreadystatechange = function(){
if (s.readyState == "loaded" ||
s.readyState == "complete"){
s.onreadystatechange = null;
callback();
}
};
} else { //Others
s.onload = function(){
callback();
};
}
}
s.src = src;
target.appendChild(s);
}
var elFrame = document.getElementById('#iframe');
$(elFrame).load(function(){
var context = this.contentDocument;
var frameHead = context.getElementsByTagName('head').item(0);
insertScript(context, frameHead, '/js/somescript.js');
}

Bookmarklet wait until Javascript is loaded

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.

Categories

Resources