Skip to main content

How do you dynamically load a javascript file? (Think C"s #include)


How can you reliably and dynamically load a javascript file? This will can be used to implement a module or component that when 'initialized' the component will dynamically load all needed javascript library scripts on demand.



The client that uses the component isn't required to load all the library script files (and manually insert tags into their web page) that implement this component - just the 'main' component script file.



How do mainstream javascript libraries accomplish this (Prototype, jquery, etc)? Do these tools merge multiple javascript files into a single redistributable 'build' version of a script file? Or do they do any dynamic loading of ancillary 'library' scripts?



An addition to this question --- is there a way to handle the event after a dynamically included javascript file is loaded? Prototype has document.observe for document-wide events. Example:




document.observe("dom:loaded", function() {
// initially hide all containers for tab content
$$('div.tabcontent').invoke('hide');
});



What are the available events for a script element?


Source: Tips4allCCNA FINAL EXAM

Comments

  1. I did basically the same thing that you did Adam, but with a slide modification to make sure I was appending to the head tag to get the job done. I simply created an include function (code below) to handle both script and css files.

    This function also checks to make sure that the script or CSS file hasn't already been loaded dynamically. It does not check for hand coded values and there may have been a better way to do that, but it served the purpose.

    function include( url, type ){
    // First make sure it hasn't been loaded by something else.
    if( Array.contains( includedFile, url ) )
    return;

    // Determine the MIME-type
    var jsExpr = new RegExp( "js$", "i" );
    var cssExpr = new RegExp( "css$", "i" );
    if( type == null )
    if( jsExpr.test( url ) )
    type = 'text/javascript';
    else if( cssExpr.test( url ) )
    type = 'text/css';

    // Create the appropriate element.
    var tag = null;
    switch( type ){
    case 'text/javascript' :
    tag = document.createElement( 'script' );
    tag.type = type;
    tag.src = url;
    break;
    case 'text/css' :
    tag = document.createElement( 'link' );
    tag.rel = 'stylesheet';
    tag.type = type;
    tag.href = url;
    break;
    }

    // Insert it to the <head> and the array to ensure it is not
    // loaded again.
    document.getElementsByTagName("head")[0].appendChild( tag );
    Array.add( includedFile, url );
    }

    ReplyDelete
  2. I used a much less complicated version recently with jQuery:

    <script src="scripts/jquery.js" type="text/javascript"></script>
    <script type="text/javascript">//<![CDATA[
    var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"];
    var $head = $("head");
    for (var i = 0; i < js.length; i++) $head.append("<script src=\"" + js[i] + "\" type=\"text/javascript\"></scr" + "ipt>");
    //]]></script>


    It worked great in every browser I tested it in: IE6/7, Firefox, Safari, Opera.

    Update: jQuery-less version:

    <script type="text/javascript">//<![CDATA[
    var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"];
    for (var i = 0, l = js.length; i < l; i++) document.getElementsByTagName("head")[0].innerHTML += ("<script src=\"" + js[i] + "\" type=\"text/javascript\"></scr" + "ipt>");
    //]]></script>

    ReplyDelete
  3. Here is some example code I've found... does anyone have a better way?

    function include(url)
    {
    var s = document.createElement("script");
    s.setAttribute("type", "text/javascript");
    s.setAttribute("src", url);
    var nodes = document.getElementsByTagName("*");
    var node = nodes[nodes.length -1].parentNode;
    node.appendChild(s);
    }

    ReplyDelete
  4. Just found out about a great feature in YUI 3 (at the time of writing available in preview release). You can easily insert dependencies to YUI libraries and to "external" modules (what you are looking for) without too much code: YUI Loader.

    It also answers your second question regarding the function being called as soon as the external module is loaded.

    Example:

    YUI({
    modules: {
    'simple': {
    fullpath: "http://example.com/public/js/simple.js"
    },
    'complicated': {
    fullpath: "http://example.com/public/js/complicated.js"
    requires: ['simple'] // <-- dependency to 'simple' module
    }
    },
    timeout: 10000
    }).use('complicated', function(Y, result) {
    // called as soon as 'complicated' is loaded
    if (!result.success) {
    // loading failed, or timeout
    handleError(result.msg);
    } else {
    // call a function that needs 'complicated'
    doSomethingComplicated(...);
    }
    });


    Worked perfectly for me and has the advantage of managing dependencies. Refer to the YUI documentation for an example with YUI 2 calendar.

    ReplyDelete
  5. does anyone have a better way?


    I think just adding the script to the body would be easier then adding it to the last node on the page. How about this:

    function include(url) {
    var s = document.createElement("script");
    s.setAttribute("type", "text/javascript");
    s.setAttribute("src", url);
    document.body.appendChild(s);
    }

    ReplyDelete
  6. i've used yet another solution i found on the net ... this one is under creativecommons and it checks if the source was included prior to calling the function ...

    you can find the file here: include.js

    /** include - including .js files from JS - bfults@gmail.com - 2005-02-09
    ** Code licensed under Creative Commons Attribution-ShareAlike License
    ** http://creativecommons.org/licenses/by-sa/2.0/
    **/
    var hIncludes = null;
    function include(sURI)
    {
    if (document.getElementsByTagName)
    {
    if (!hIncludes)
    {
    hIncludes = {};
    var cScripts = document.getElementsByTagName("script");
    for (var i=0,len=cScripts.length; i < len; i++)
    if (cScripts[i].src) hIncludes[cScripts[i].src] = true;
    }
    if (!hIncludes[sURI])
    {
    var oNew = document.createElement("script");
    oNew.type = "text/javascript";
    oNew.src = sURI;
    hIncludes[sURI]=true;
    document.getElementsByTagName("head")[0].appendChild(oNew);
    }
    }
    }

    ReplyDelete
  7. The technique we use at work is to request the javascript file using an AJAX request and then eval() the return. If you're using the prototype library, they support this functionality in their Ajax.Request call.

    ReplyDelete
  8. jquery resolved this for me with its .append() function
    - used this to load the complete jquery ui package

    /*
    * FILENAME : project.library.js
    * USAGE : loads any javascript library
    */
    var dirPath = "../js/";
    var library = ["functions.js","swfobject.js","jquery.jeditable.mini.js","jquery-ui-1.8.8.custom.min.js","ui/jquery.ui.core.min.js","ui/jquery.ui.widget.min.js","ui/jquery.ui.position.min.js","ui/jquery.ui.button.min.js","ui/jquery.ui.mouse.min.js","ui/jquery.ui.dialog.min.js","ui/jquery.effects.core.min.js","ui/jquery.effects.blind.min.js","ui/jquery.effects.fade.min.js","ui/jquery.effects.slide.min.js","ui/jquery.effects.transfer.min.js"];

    for(var script in library){
    $('head').append('<script type="text/javascript" src="' + dirPath + library[script] + '"></script>');
    }


    To Use - in the head of your html/php/etc after you import jquery.js you would just include this one file like so to load in the entirety of your library appending it to the head...

    <script type="text/javascript" src="project.library.js"></script>

    ReplyDelete
  9. Is Rhino one of these tools?


    Rhino is just a JavaScript Engine. Over at Wikipedia they say that (JavaScript_engine)">Rhino is one of Mozilla's ECMA-262 Edition 3 compliant JavaScript Engines. Its most unique quality is that it was written in Java and is open source. You can download the free Java libraries and run a Rhino Javascript Shell right from your terminal. This is quite useful. You can do the same with (Javascript_engine)">SpiderMonkey another Mozilla JavaScript engine that is written in C.

    ReplyDelete
  10. I guess they have tools that merge multiple javascript files into a single redistributable 'build' version of a script file?


    This may be a little off topic but I'll throw it out there.

    There is a neat way that you can do this on the server side. If you wanted to do this dynamically you would craft a request to the server's script listing the files on in the URL like query parameters. The server script can than combine the scripts together and returns them in a single script.

    The one that I am most familiar with can be found by googling combine.php. That article goes above and beyond by using URL Rewriting to make the syntax easier to construct, but the idea still stands that you can reduce the size of files and reduce the number of requests. As always you should be gzipping javascript responses.



    Sorry for the multiple posts. It just seems like there are multiple questions =)

    ReplyDelete
  11. all the major javascript libraries like jscript, prototype, YUI have support for loading script files. For example, in YUI, after loading the core you can do the following to load the calendar control

    var loader = new YAHOO.util.YUILoader({

    require: ['calendar'], // what components?

    base: '../../build/',//where do they live?

    //filter: "DEBUG", //use debug versions (or apply some
    //some other filter?

    //loadOptional: true, //load all optional dependencies?

    //onSuccess is the function that YUI Loader
    //should call when all components are successfully loaded.
    onSuccess: function() {
    //Once the YUI Calendar Control and dependencies are on
    //the page, we'll verify that our target container is
    //available in the DOM and then instantiate a default
    //calendar into it:
    YAHOO.util.Event.onAvailable("calendar_container", function() {
    var myCal = new YAHOO.widget.Calendar("mycal_id", "calendar_container");
    myCal.render();
    })
    },

    // should a failure occur, the onFailure function will be executed
    onFailure: function(o) {
    alert("error: " + YAHOO.lang.dump(o));
    }

    });

    // Calculate the dependency and insert the required scripts and css resources
    // into the document
    loader.insert();

    ReplyDelete
  12. If you have jQuery loaded already, you should use $.getScript.

    This has an advantage over the other answers here in that you have a built in callback function (to guarantee the script is loaded before the dependant code runs) and you can control caching.

    ReplyDelete
  13. There are scripts that are designed specifically for this purpose.

    yepnope.js is built into Modernizr, and lab.js is a more optimized (but less user friendly version.

    I wouldn't reccomend doing this through a big library like jquery or prototype - because one of the major benefits of a script loader is the ability to load scripts early - you shouldn't have to wait until jquery & all your dom elements load before running a check to see if you want to dynamically load a script.

    ReplyDelete
  14. If you attempt to load a JavaScript file outside of the head tag you will break w3c and xhtml standards.

    You will also lose Opera and konqueror support.

    ReplyDelete

Post a Comment

Popular posts from this blog

[韓日関係] 首相含む大幅な内閣改造の可能性…早ければ来月10日ごろ=韓国

div not scrolling properly with slimScroll plugin

I am using the slimScroll plugin for jQuery by Piotr Rochala Which is a great plugin for nice scrollbars on most browsers but I am stuck because I am using it for a chat box and whenever the user appends new text to the boxit does scroll using the .scrollTop() method however the plugin's scrollbar doesnt scroll with it and when the user wants to look though the chat history it will start scrolling from near the top. I have made a quick demo of my situation http://jsfiddle.net/DY9CT/2/ Does anyone know how to solve this problem?

Why does this javascript based printing cause Safari to refresh the page?

The page I am working on has a javascript function executed to print parts of the page. For some reason, printing in Safari, causes the window to somehow update. I say somehow, because it does not really refresh as in reload the page, but rather it starts the "rendering" of the page from start, i.e. scroll to top, flash animations start from 0, and so forth. The effect is reproduced by this fiddle: http://jsfiddle.net/fYmnB/ Clicking the print button and finishing or cancelling a print in Safari causes the screen to "go white" for a sec, which in my real website manifests itself as something "like" a reload. While running print button with, let's say, Firefox, just opens and closes the print dialogue without affecting the fiddle page in any way. Is there something with my way of calling the browsers print method that causes this, or how can it be explained - and preferably, avoided? P.S.: On my real site the same occurs with Chrome. In the ex