tags:

views:

190

answers:

7

Hi guys,

I'm wondering if you guys can help me to perform on-demand javascript using AJAX? If you can help me with a simple example, I would really appreciate it.

my question is: how to get a javascript code from my server and execute it?

Thanks for the help

A: 

Get the JavaScript code from the server enclosed in tags, append it into DOM and execute a function. The function name to execute could come with the same request or it can be predefined.

What do need this for? Perhaps if you could elaborate your goals, a more straightforward method could be found.

Tatu Ulmanen
actually as I explained to Andrew Moore, I'm programming a home page completely depending on AJAX. I don't want any page reloading or page refreshing. So, from time to time I need to add and use javascript codes as needed. If I append it into DOM then I have to execute the code on as a function becuase there is no page reloading so the head part will not be read again and again. Sometime I need to get new js file which contains new variable or changing the action event of an HTML element. I hope the idea is now more clear.
codemaker
+6  A: 

In fact, you don't even need to use AJAX for this. Simply append a new <script> element to your body.

Plain Old Javascript:

var newScript = document.createElement('script');
newScript.type = 'text/javascript';
newScript.src = '/scripts/example.js';

document.body.appendChild(newScript);

Here's the same code using jQuery:

// Traditional
$(document.body)
  .append('<script type="text/javascript" src="/scripts/example.js" />');

// Using getScript
$.getScript('/scripts/example.js');

Here's the same code using MooTools:

// Traditional
new Element('script', {type: 'text/javascript',
                       src: '/scripts/example.js'}
           ).inject(document.body);

// Using Assets (Recommended)
new Asset.javascript('/scripts/example.js');
Andrew Moore
+1 Great answer, and for including sample code
Doug Neiner
With jQuery I would recommend you to use the $.getScript method.
CMS
I really like that Mootools Asset class.
jpartogi
I would also recommend the OP to take care of removing the injected `script` elements after they're loaded, due possible memory leaks: http://is.gd/5ejNi
CMS
actually I'm trying to build a home page for a website completely depending on AJAX. Now, If I try to append a new <script> to the head each time I want to get a javascript code, that might help but I have to call the appended function or code by using javascript events because the browser will not interpret the head part of the page because I don't want to reload the page. That's why I need sometimes to run the code as soon as I get it like assigning new variables or changing the event of one of the HTML elements. Any ideas??
codemaker
Append it to the body instead.
Andrew Moore
**@CMS:** Thanks, I usually develop with MooTools so I wasn't aware of `$.getScript`
Andrew Moore
A: 

Javascript gets from the web server to the user's browser in a couple of ways:

  • It is embedded in the web page along with the HTML in a <script> tag
  • It is sent as a separate file along with the web page. The javascript file has a file name extension of .js. The code in the web page <script> tags can call the code in this separate .js file
  • A combination of these can be used. The common javascript functions that are used on many web pages go in the .js file. Javascript that's only used on one web page goes on that page.
DOK
+1  A: 

I made the following function for being able to load JavaScript files programmatically:

Usage:

loadScript('http://site.com/js/libraryXX.js', function () {
  alert('libraryXX loaded!');
});

Implementation:

function loadScript(url, callback) {
  var head = document.getElementsByTagName("head")[0],
      script = document.createElement("script"),
      done = false;

  script.src = url;

  // Attach event handlers for all browsers
  script.onload = script.onreadystatechange = function(){
    if ( !done && (!this.readyState ||
      this.readyState == "loaded" || this.readyState == "complete") ) {
      done = true;
      callback(); // execute callback function

      // Prevent memory leaks in IE
      script.onload = script.onreadystatechange = null;
      head.removeChild( script );
    }
  };
  head.appendChild(script);
}

I use a callback function argument, that will be executed when the script is loaded properly.

Also notice that the script element is removed from the head after it is loaded and I remove the load and readystatechange events by setting them to null, that is made to prevent memory leaks on IE.

Check an example usage here.

CMS
+1  A: 

I use this code to load-on-demand (using jQuery). Its blocking (but i need it) you can make it synchronous using async:true

(function(script) {
    var included_files = new Array();
    this.include = function(script) {
        var js_base = '/js/';
        if (_.indexOf(included_files, script) == -1){
            included_files.push(script);
            $.ajax({
                url: js_base+script.split('.').join('/')+'.js',
                type: 'get',
                dataType: 'script',
                async: false,
                global:false,
            });
        }
    };
})();

It uses jQuery and Underscore.js for .indexOf but you can ommit latter with your own indexOf function.
Good luck.

NilColor
I love underscore.js, but jQuery has $.inArray() for that.
Nosredna
Some explanation - i have this snippet in utils.js which is included in page header so `this` is window here. After all i have a global function `include` that can load other js file with `include('foo.bar')` call. This sample call means that /js/foo/bar.js file will be loaded immediately and become ready to use right after include call.
NilColor
@Nosredna i know... But i prefer to use Underscore as much as possible.
NilColor
A: 

CMS has shown a solid (looking, haven't tested) library independent method. Here's how you do it in Dojo.

dojo.require("namespace.object");

You may need to specifiy the path to your namespace (ie: root folder)

dojo.registerModulePath("namespace", "../some/folder/path");

See the doc for more info.

Justin Johnson
+1  A: 

If you really want to use AJAX (as stated in the question) you can do so too. First, you download the javascript normally using XMLHttpRequest and when the download is finished you either eval() it or insert it inside a generated tag.

function xhr_load(url, callback) {
  xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
      if (xhr.status == 200) {
        callback(xhr.responseText);
      } 
    }
  }
  xhr.open("GET", url, true);
  xhr.send(null);
}

// (1) download using XHR and execute using eval()
xhr_load('mylib.js', function(response) {
  eval(response.responseText);
});

// (2) download using XHR and execute as an inline script
xhr_load('mylib.js', function(response) {
  var script = 
    document.createElement('script');
    document.getElementsByTagName('head')[0].appendChild(script);
    script.text = response.responseText;
});

Also, Steve Souders has done amazing job in this field and I can highly recommend watching his talk on this video.

jedi
Great but would you explain more about the callback? Is it safe to use eval function?
codemaker
Would someone please help me explain what is the purpose of the callback?
codemaker
it is because the communication is asynchronous. It can complete at anytime, therefore when the communication finishes it has to know what to execute
Gutzofter
@codemaker: you are right in that using eval() is usually not recommended as it raises security and performance concerns. However, this is one of the places where (i think) it is acceptable to use eval(). But I'd still probably recommend using the second (2) option because when using eval(), you have to be careful that you do it in proper (probably global in your case) scope.
jedi