views:

1278

answers:

5

I have a JS function that may occasionally get used on some pages. It is dependent on another JS file (swfObject.js), but I'd like to avoid having to include this file all over the place, as thats a wasted request most of the time.

Instead, I'd like to create a generic function that can inject a script reference into the page DOM as needed, so if this function is called, it would check for the script, and if it does not exist, load it in.

I'm fairly sure this is possible (and I'm not going to use document.write), but before I venture off into uncharted territory, has anyone done this before, and if so, any pointers?

EDIT: Ok, I tried it, and it works in IE6 and FF, I haven't tested other browsers yet.

Here is my code (Rev 2.0, now with optional callbacks):

function loadJSInclude(scriptPath, callback)
{
    var scriptNode = document.createElement('SCRIPT');
    scriptNode.type = 'text/javascript';
    scriptNode.src = scriptPath;

    var headNode = document.getElementsByTagName('HEAD');
    if (headNode[0] != null)
        headNode[0].appendChild(scriptNode);

    if (callback != null)    
    {
        scriptNode.onreadystagechange = callback;            
        scriptNode.onload = callback;
    }
}

and in the method with a dependency:

var callbackMethod = function ()
{
    // Code to do after loading swfObject
}

// Include SWFObject if its needed
if (typeof(SWFObject) == 'undefined')    
    loadJSInclude('/js/swfObject.js', callbackMethod);
else
    calbackMethod();

Any suggestions?

A: 

Checkout the YUI Loader utility. It's super handy, unobtrusive javascript for loading scripts on-demand.

Here's a link to an example using non-YUI scripts:

http://developer.yahoo.com/yui/examples/yuiloader/yl-addmodule.html

Jim Fiorato
+2  A: 

If you're using a higher level framework such as JQuery, you could check out the $.getScript(url, callback) function.

abahgat
A: 

You can add a new script element to the DOM, something like

function include_js(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;
}

If you need to know when the script has been downloaded and is ready to use, you'll want something like this.

stevemegson
You don't really have to stick it into the head. It can be stuck into the body. What you will want to do is add a callback to the end of the swfobject file so that your original javascript knows the swfobject is good to go.
Sugendran
+2  A: 

If you want your code on the very next line and like to write something like:

if (iNeedSomeMore){
  Script.load("myBigCodeLibrary.js");  // includes code for myFancyMethod();
  myFancyMethod();                     // cool, no need for callbacks!
}

There is a smart way to inject script dependencies without the need of callbacks. You simply have to pull the script via a synchronous AJAX request and eval the script on global level.

If you use Prototype the Script.load method looks like this:

var Script = {
  _loadedScripts: [],
  include: function(script){
    // include script only once
    if (this._loadedScripts.include(script)){
      return false;
    }
    // request file synchronous
    var code = new Ajax.Request(script, {
      asynchronous: false, method: "GET",
      evalJS: false, evalJSON: false
    }).transport.responseText;
    // eval code on global level
    if (Prototype.Browser.IE) {
      window.execScript(code);
    } else if (Prototype.Browser.WebKit){
      $$("head").first().insert(Object.extend(
        new Element("script", {type: "text/javascript"}), {text: code}
      ));
    } else {
      window.eval(code);
    }
    // remember included script
    this._loadedScripts.push(script);
  }
};
aemkei
Yeah, I prefer my method, plus my method works for cross domain scripts.
FlySwat
What's with all the browser sniffing?
kangax
You're right kangax! But I was not able to evaluate the returned code within the global "window" scope. Especially WebKit messed up some things.
aemkei
A: 

None of these methods, including document.writing a script tag, work if the script itself has a document.write in it.