Can't include more than one js file. Onload event fires only for the last file but as many times as I have files. How to solve it?

StackOverflow https://stackoverflow.com/questions/13241610

Question

I want to append several js files dynamically. Each file has a function definition and I want to save its code in the property of an object. I use plain JavaScript and script tag. But onload event doesn't work right. If I include just one file everything works fine. But if more than one, onload is out of order. Here's my code, it is method in the object:

// My files I want to include:
one.js
   function one() { alert('one') };

two.js
   function two() { alert('two') };

// My code in the object 
var one = null;
var two = null;   // In these properties I want to save my functions

function inc(files) {   // 'files' is the object {one: 'one', two: 'two'}
                        'one' and 'two' are names of function in my files
    for (key in files) {

       var script = document.createElement('script');
       script.setAttribute('type', 'text/javascript');

       var fullPath = '/path/to/file/' + files[key] + '.js';   // /path/to/file/one.js, /path/to/file/two.js,
       script.setAttribute('src', fullPath);


       // And here's my eventhandler. After the script is loaded,
       // names of my functions are in global scope. So, the task is:
       // to take them and save in properties using setter.
       script.onload = function() {

           setProps(window[files[key]]);   // setProp(window.one / window.two);
           window[files[key]] = null;      // remove them from global scope

           alert(one/two);   // to check if I have functions saved in properties
       }

       document.getElementsByTagName('head').item(0).appendChild(script);

    };
};

As I said at the beginning, everything works fine if I load one file. But for more than one the onload works twice but only for my second file - with function 'two' definition. Alert fires twice and shows the code of 'two'. And I have only function 'two' im my property 'two', the last one I passed with parameter. And files are appended in DOM just file.

I've tried to create <script> tag outside of for/in loop, and even created an array and saved each of two scripts as separate elements of that array but it doesn't help either - only the last file is in the onload and twice.

What is the problem? Why doesn't it work for two files? Is it possible to solve it?

Was it helpful?

Solution

It's hard to tell when you don't include complete code, but it's likely that you're running into a closure problem.

You have your onload function defined inside the for loop, which means it'll bind a reference to the "key" local variable. By the time the "unload" function actually runs, the for loop will have been completed, and "key" will be "two", so you'll see "two" in both alerts.

Here's a more-trivial example of the same problem:

for (x=0; x< 2; x++) {
   setTimeout(function() {
       alert(x);
   }, 100);
}

when you run this, you'll get two alerts, each of which shows "2", which is the value of "x" after the loop exits.

To fix this, you need to invoke a function which returns the function you want to call when the timeout happens:

function create_alerter(z) {
    return function() {
        alert("fixed: " + z);
    }
}

for (x = 0; x < 2; x++) {
    setTimeout(create_alerter(x), 100);
}

If you don't like having a separate function for this, you can define the function-returning function and invoke it inline:

for (x = 0; x < 2; x++) {
    setTimeout(function(z) {
       return function() {
          alert(z);
       }
    }(x), 100);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top