views:

290

answers:

3

I was implementing a on-demand script controller based on jquery's getscript, it looks like this:

function controller = function(){

   var script = function(){
      var scripts = {};
      return {
        load: function(jsurl){
          $.getScript(jsurl, null);
        },
        run: function(js){
          window[js].apply(this,null);
        }
      }
   };

  return {
    script: script()
  };

}

var ctlr = controller();

then here is a remote script with a function to be loaded - remote.js

function remotefunc(){
  alert( 'remotefunc invoked' );
}

and here is how the whole thing supposed to work, in the main script:

ctlr.script.load( 'remote.js' ); // remote script successfully loaded
ctlr.script.run( 'remotefunc' ); // got an error, window['remotefunc'] undefined

but as you can see, 'remotefunc' is defined in the global 'window' scope, so the window object is supposed to be able to 'see' it.

I thought the problem was probably the closure stuff in the 'controller' definition, so I did a direct $.getScirpt without using the 'controller':

$.getScript( 'http://path/to/remote.js', function(){
  window['remotefunc'].apply( this, null );  // this worked
} );

strange. So it is about the 'controller' implementation(I kind need it)! Anybody can help me out with this? How to fix the 'controller' implementation so the

 window[js].apply(this,null);

can actually work?

Thanx.

+2  A: 

The reason it's telling you window['remotefunc'] is undefined is because you are not giving it time to actually download and execute the remote script before attempting to call a function defined in it.

The remote script is loaded asynchronously, which means the script execution isn't paused while waiting for a response.

You will need to either re-implement the getScript method to be synchronous or somehow work your class around the fact that the function will not be available in any determinate amount of time.

EDIT: Just found another possible solution, try calling this before your request

$.ajaxSetup({async: false});

This will make the getScript method synchronous

Kane Wallmann
I wouldn't do make the method synchronous. The entire point of doing it asynchronously is so that execution is not blocking on network delay.
thedz
@Kane: Thanks! Put your code before $.getScript, problem remains though
Shawn
A: 

Could this be a timing issue?

In your working example you call the function in a callback which jQuery will not invoke until the script is loaded. In your non-working example, you call the function immediately after getScript which is asynchronously loading the script.

Hans B PUFAL
+1  A: 

When using something like getSript, it's important to remember that it is fetching asynchronously. Meaning, the browser fires off the request and while that's happening, code after that line executes without pause.

jQuery provides a callback function parameter to get script that allows you to do something after the asynchronous fetch is finished.

Try this:

 var script = function(){
      var scripts = {};
      return {
           load: function(jsurl, callback){
                $.getScript(jsurl, callback);
           },
           run: function(js){
                window[js].apply(this,null);
           }
     }
 };

Then, when using it:

 ctlr.load( 'remote.js', function(){
      // remote script successfully loaded
      ctlr.run( 'remotefunc' ); 
 });
thedz