Fluidbyte
Fluidbyte

Reputation: 5210

Maintain scope when loading script with jQuery

Say I have a file 'test.js' with the following contents:

var test = 'something';

Then I have a primary script that needs to load up test.js to grab the test variable.

Obviously this works:

$.ajax({dataType: "script", cache: true, url: 'test.js'});

The issue is that the variable test exists in the global scope. I'm curious if there's a way to add it into an object and keep it out of the global scope.

Something like:

function scriptloader() {
    this.grabscript = function() {
        return $.ajax({dataType: "script", cache: true, url: 'test.js'});
    }
}

var myloader = new scriptloader();

myloader.grabscript();

Where ideally myloader would contain the loaded variable test. However, I can console.log(test) and still see 'something'.

Is there a way to lock the loaded script into scope or am I dreaming?

Upvotes: 4

Views: 3459

Answers (4)

user2594579
user2594579

Reputation:

you could try to extend an object that already exists on your page.

Say you have a script on your page like this

var app = {
    loadedScripts
    ,loadPageScript : function(scriptUrl, cb) {
        $.getScript(scriptUrl, cb)
            .fail(function( jqxhr, settings, exception ) {
                console.log(exception);
        })
    }
}

app.loadPageScript('/test.js', function(){
    app.loadedScripts['test']();
});

Your test.js file:

if(!app.loadedScripts.test){
    app.loadedScripts.test = function() {

        app.someVar = 1;

        app.someFunction = function(){
            console.log('iha');
        };
    }
}

Upvotes: 0

rlkw1024
rlkw1024

Reputation: 6515

You could try something like this:

function scriptloader() {
  this.grabscript = function() {
    var loader = this;
    $.ajax('test.js', {
      complete: function(response) {
        var js = '(function() {' + response.responseText + ' loader.test = test; })();'
        eval(js);
      },
      dataType: 'text'
    });
  }
}

The scriptloader instance would then get a property called test.

Upvotes: 3

Christophe
Christophe

Reputation: 28154

If you have no control over test.js, and must accept that test is declared as a global variable, a workaround would be to load test.js in an iframe within your page. This way test will be a global variable but only within the scope of the iframe window. From your main page, you'll be able to access it as ifr.contentWindow.test.

Upvotes: 1

Bergi
Bergi

Reputation: 664650

You could use eval for that purpose and create a variable with the expected name in the local scope:

(function(jsString) {
    var test;
    eval(jsString);
    console.log(test); // 'something'
})("var test = 'something';");
console.log(test); // Exception: undefined variable

You then need to use that custom function instead of $.globalEval (code) as used in ajax for scripts.

Of course this is not a catch-all method for every global variable, for something like that you would need to create a separate global object (e.g. with an <iframe>) to evalute the script there.

However, using JSONP might be a better idea than using variables.

Upvotes: 1

Related Questions