I have a dynamic web page where I need to import an external JS file (under an IF condition) inside another javascript file.
I tried to search for a feasible solution but it didn't work.
I have tried loading a JS file to the DOM using document.createElement() but it also didn't work. Apparently the Js was loaded into the DOM but was not accessible in the current JS file.
Solution in jQuery will also be fine
312 Answers
My guess is that in your DOM-only solution you did something like:
var script = document.createElement('script'); script.src = something; //do stuff with the script First of all, that won't work because the script is not added to the document tree, so it won't be loaded. Furthermore, even when you do, execution of javascript continues while the other script is loading, so its content will not be available to you until that script is fully loaded.
You can listen to the script's load event, and do things with the results as you would. So:
var script = document.createElement('script'); script.onload = function () { //do stuff with the script }; script.src = something; document.head.appendChild(script); //or something of the likes 14jQuery's $.getScript() is buggy sometimes, so I use my own implementation of it like:
jQuery.loadScript = function (url, callback) { jQuery.ajax({ url: url, dataType: 'script', success: callback, async: true }); } and use it like:
if (typeof someObject == 'undefined') $.loadScript('url_to_someScript.js', function(){ //Stuff to do after someScript has loaded }); 4I need to do this frequently, so I use this:
var loadJS = function(url, implementationCode, location){ //url is URL of external file, implementationCode is the code //to be called from the file, location is the location to //insert the <script> element var scriptTag = document.createElement('script'); scriptTag.src = url; scriptTag.onload = implementationCode; scriptTag.onreadystatechange = implementationCode; location.appendChild(scriptTag); }; var yourCodeToBeCalled = function(){ //your code goes here } loadJS('yourcode.js', yourCodeToBeCalled, document.body); For more information, see this site How do I include a JavaScript file in another JavaScript file?, which is the source of my function idea.
4You may dynamically load the js inside the page not another js file.
You have to use the getScript to load the js file.
$.getScript("ajax/test.js", function(data, textStatus, jqxhr) { console.log(data); // data returned console.log(textStatus); // success console.log(jqxhr.status); // 200 console.log('Load was performed.'); }); 2Necromancing.
I use this to load dependant scripts;
it works with IE8+ without adding any dependency on another library like jQuery !
var cScriptLoader = (function () { function cScriptLoader(files) { var _this = this; this.log = function (t) { console.log("ScriptLoader: " + t); }; this.withNoCache = function (filename) { if (filename.indexOf("?") === -1) filename += "?no_cache=" + new Date().getTime(); else filename += "&no_cache=" + new Date().getTime(); return filename; }; this.loadStyle = function (filename) { // HTMLLinkElement var link = document.createElement("link"); link.rel = "stylesheet"; link.type = "text/css"; link.href = _this.withNoCache(filename); _this.log('Loading style ' + filename); link.onload = function () { _this.log('Loaded style "' + filename + '".'); }; link.onerror = function () { _this.log('Error loading style "' + filename + '".'); }; _this.m_head.appendChild(link); }; this.loadScript = function (i) { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = _this.withNoCache(_this.m_js_files[i]); var loadNextScript = function () { if (i + 1 < _this.m_js_files.length) { _this.loadScript(i + 1); } }; script.onload = function () { _this.log('Loaded script "' + _this.m_js_files[i] + '".'); loadNextScript(); }; script.onerror = function () { _this.log('Error loading script "' + _this.m_js_files[i] + '".'); loadNextScript(); }; _this.log('Loading script "' + _this.m_js_files[i] + '".'); _this.m_head.appendChild(script); }; this.loadFiles = function () { // this.log(this.m_css_files); // this.log(this.m_js_files); for (var i = 0; i < _this.m_css_files.length; ++i) _this.loadStyle(_this.m_css_files[i]); _this.loadScript(0); }; this.m_js_files = []; this.m_css_files = []; this.m_head = document.getElementsByTagName("head")[0]; // this.m_head = document.head; // IE9+ only function endsWith(str, suffix) { if (str === null || suffix === null) return false; return str.indexOf(suffix, str.length - suffix.length) !== -1; } for (var i = 0; i < files.length; ++i) { if (endsWith(files[i], ".css")) { this.m_css_files.push(files[i]); } else if (endsWith(files[i], ".js")) { this.m_js_files.push(files[i]); } else this.log('Error unknown filetype "' + files[i] + '".'); } } return cScriptLoader; })(); var ScriptLoader = new cScriptLoader(["foo.css", "Scripts/Script4.js", "foobar.css", "Scripts/Script1.js", "Scripts/Script2.js", "Scripts/Script3.js"]); ScriptLoader.loadFiles(); If you are interested in the typescript-version used to create this:
class cScriptLoader { private m_js_files: string[]; private m_css_files: string[]; private m_head:HTMLHeadElement; private log = (t:any) => { console.log("ScriptLoader: " + t); } constructor(files: string[]) { this.m_js_files = []; this.m_css_files = []; this.m_head = document.getElementsByTagName("head")[0]; // this.m_head = document.head; // IE9+ only function endsWith(str:string, suffix:string):boolean { if(str === null || suffix === null) return false; return str.indexOf(suffix, str.length - suffix.length) !== -1; } for(let i:number = 0; i < files.length; ++i) { if(endsWith(files[i], ".css")) { this.m_css_files.push(files[i]); } else if(endsWith(files[i], ".js")) { this.m_js_files.push(files[i]); } else this.log('Error unknown filetype "' + files[i] +'".'); } } public withNoCache = (filename:string):string => { if(filename.indexOf("?") === -1) filename += "?no_cache=" + new Date().getTime(); else filename += "&no_cache=" + new Date().getTime(); return filename; } public loadStyle = (filename:string) => { // HTMLLinkElement let link = document.createElement("link"); link.rel = "stylesheet"; link.type = "text/css"; link.href = this.withNoCache(filename); this.log('Loading style ' + filename); link.onload = () => { this.log('Loaded style "' + filename + '".'); }; link.onerror = () => { this.log('Error loading style "' + filename + '".'); }; this.m_head.appendChild(link); } public loadScript = (i:number) => { let script = document.createElement('script'); script.type = 'text/javascript'; script.src = this.withNoCache(this.m_js_files[i]); var loadNextScript = () => { if (i + 1 < this.m_js_files.length) { this.loadScript(i + 1); } } script.onload = () => { this.log('Loaded script "' + this.m_js_files[i] + '".'); loadNextScript(); }; script.onerror = () => { this.log('Error loading script "' + this.m_js_files[i] + '".'); loadNextScript(); }; this.log('Loading script "' + this.m_js_files[i] + '".'); this.m_head.appendChild(script); } public loadFiles = () => { // this.log(this.m_css_files); // this.log(this.m_js_files); for(let i:number = 0; i < this.m_css_files.length; ++i) this.loadStyle(this.m_css_files[i]) this.loadScript(0); } } var ScriptLoader = new cScriptLoader(["foo.css", "Scripts/Script4.js", "foobar.css", "Scripts/Script1.js", "Scripts/Script2.js", "Scripts/Script3.js"]); ScriptLoader.loadFiles(); If it's to load a dynamic list of scripts, write the scripts into an attribute, such as data-main, e.g. <script src="scriptloader.js" ></script>
and do a element.getAttribute("data-main").split(',')
such as
var target = document.currentScript || (function() { var scripts = document.getElementsByTagName('script'); // Note: this is for IE as IE doesn't support currentScript // this does not work if you have deferred loading with async // e.g. <script src="..." async="async" ></script> // return scripts[scripts.length - 1]; })(); target.getAttribute("data-main").split(',') to obtain the list.
3The jQuery.getScript() method is a shorthand of the Ajax function (with the dataType attribute: $.ajax({ url: url,dataType: "script"}))
If you want the scripts to be cachable, either use RequireJS or follow jQuery's example on extending the jQuery.getScript method similar to the following.
jQuery.cachedScript = function( url, options ) { // Allow user to set any option except for dataType, cache, and url options = $.extend( options || {}, { dataType: "script", cache: true, url: url }); // Use $.ajax() since it is more flexible than $.getScript // Return the jqXHR object so we can chain callbacks return jQuery.ajax( options ); }; // Usage $.cachedScript( "ajax/test.js" ).done(function( script, textStatus ) { console.log( textStatus ); }); Reference: jQuery.getScript() | jQuery API Documentation
jQuery has $.getScript():
Description: Load a JavaScript file from the server using a GET HTTP request, then execute it.
You can do it using JQuery:
$.getScript("ajax/test.js", function(data, textStatus, jqxhr) { console.log(data); //data returned console.log(textStatus); //success console.log(jqxhr.status); //200 console.log('Load was performed.'); }); I'm recommend using requirejs with AMD javascript class files
good example of how to use it here
To author my plugin I needed to load external scripts and styles inside a JS file, all of which were predefined. To achieve this, I did the following:
this.loadRequiredFiles = function (callback) { var scripts = ['xx.js', 'yy.js']; var styles = ['zz.css']; var filesloaded = 0; var filestoload = scripts.length + styles.length; for (var i = 0; i < scripts.length; i++) { log('Loading script ' + scripts[i]); var script = document.createElement('script'); script.type = 'text/javascript'; script.src = scripts[i]; script.onload = function () { log('Loaded script'); log(this); filesloaded++; // (This means increment, i.e. add one) finishLoad(); }; document.head.appendChild(script); } for (var i = 0; i < styles.length; i++) { log('Loading style ' + styles[i]); var style = document.createElement('link'); style.rel = 'stylesheet'; style.href = styles[i]; style.type = 'text/css'; style.onload = function () { log('Loaded style'); log(this); filesloaded++; finishLoad(); }; document.head.appendChild(style); } function finishLoad() { if (filesloaded === filestoload) { callback(); } } }; More of the script in context:
function myPlugin() { var opts = { verbose: false }; ///< The options required to run this function var self = this; ///< An alias to 'this' in case we're in jQuery ///< Constants required for this function to work this.getOptions = function() { return opts; }; this.setOptions = function(options) { for (var x in options) { opts[x] = options[x]; } }; /** * @brief Load the required files for this plugin * @param {Function} callback A callback function to run when all files have been loaded */ this.loadRequiredFiles = function (callback) { var scripts = ['xx.js', 'yy.js']; var styles = ['zz.css']; var filesloaded = 0; var filestoload = scripts.length + styles.length; for (var i = 0; i < scripts.length; i++) { log('Loading script ' + scripts[i]); var script = document.createElement('script'); script.type = 'text/javascript'; script.src = scripts[i]; script.onload = function () { log('Loaded script'); log(this); filesloaded++; finishLoad(); }; document.head.appendChild(script); } for (var i = 0; i < styles.length; i++) { log('Loading style ' + styles[i]); var style = document.createElement('link'); style.rel = 'stylesheet'; style.href = styles[i]; style.type = 'text/css'; style.onload = function () { log('Loaded style'); log(this); filesloaded++; finishLoad(); }; document.head.appendChild(style); } function finishLoad() { if (filesloaded === filestoload) { callback(); } } }; /** * @brief Enable user-controlled logging within this function * @param {String} msg The message to log * @param {Boolean} force True to log message even if user has set logging to false */ function log(msg, force) { if (opts.verbose || force) { console.log(msg); } } /** * @brief Initialise this function */ this.init = function() { self.loadRequiredFiles(self.afterLoadRequiredFiles); }; this.afterLoadRequiredFiles = function () { // Do stuff }; } Here is a little lib to load javascript and CSS files dynamically:
I guess is usefull to load css and js files in order and dynamically.
Support to extend to load any lib you want, and not just the main file, you can use it to load custom files.
I.E.:
<html> <head> <script src="//"></script> <script src="scripts/javascript-loader.js" type="text/javascript" charset="utf-8" ></script> <script type="text/javascript"> $(function() { registerLib("threejs", test); function test(){ console.log(THREE); } registerLib("tinymce", draw); function draw(){ tinymce.init({selector:'textarea'}); } }); </script> </head> <body> <textarea>Your content here.</textarea> </body> 0If you have many files with dependencies, use AMD/RequireJS.