Billa
Billa

Reputation: 5266

How javascript detects where the function is defined, top/bottom?

I have the below code is working as long as I load the employee section and its scripts as part of the index.html

index.html Working Demo

<!DOCTYPE html>
<html>

  <head>
    <meta charset="utf-8" />
    <title></title>
    <link rel="stylesheet" href="style.css" />
    <script data-require="jquery" data-semver="2.1.3" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
    <script src="script.js"></script>
  </head>

  <body>
    <h1>Employee Details loaded as usual and sript is executing able to see alert</h1>
  </body>

</html>

Script.js

var empModule = (function (empModule) {
    var Years = null;

    $(document).ready(function () {
        var empdata = { Name: 'Billa' }
        var myVM = new empModule.viewModel(empdata);

    });

    empModule.viewModel = function (data) {
        var that = this;
        that.Name = data.Name;
        alert(that.Name);
    };   

    return {
        empModule: empModule
    }
} (empModule || {}));            

Error Scenario:

We decide to move employee related section based on some condition. Hence we are loading this section and section related script(emp.js) via Ajax. But now it is throwing the error empModule.viewModel is not a constructor. Why is it so?

If I move the document.ready section at the bottom like the below order, it is working

Emp.js(moved from script.js to emp.js and load via ajax(

var empModule = (function (empModule) {
var Years = null;
// Code not working when we load this script file using Ajax.            
// But works if we move this document.ready at bottom 
//$(document).ready(function () {
  //  var empdata = { Name: 'Billa' }
  //  var myVM = new empModule.viewModel(empdata);

//});
empModule.viewModel = function (data) {
    var that = this;
    that.Name = data.Name;
    alert(that.Name);
};
//Working only if I keep the ready section here
$(document).ready(function () {
    var empdata = { Name: 'Billa' }
    var myVM = new empModule.viewModel(empdata);

});

return {
    empModule: empModule
}
} (empModule || {})); 

The function empModule will get executed automatically as it is self executing function. When it is executing it needs to prepare a empModule.viewModel object, but failed to do that when viewModel definition is located after document.ready (caller). This happens only when I load this script via Ajax, but works if I pre load it in a page

Upvotes: 0

Views: 632

Answers (2)

dougajmcdonald
dougajmcdonald

Reputation: 20057

This is because in the first example the script.js is part of the document and therefore the document.ready waits for that .js file to be loaded before trying to call empModule.viewModel().

In the second example, your script is loaded asyncronously, but the page is not taking this into account. So the page loads (without the script.js) and then you load the script. At this point, the document is ready (as the ajax loaded script isn't part of the document) so the empModule.viewModel() call fires straight away, before the rest of the script (which is the bit that defines the function) and you get your error.

Upvotes: 1

Just like @dougajmcdonald said is your issue, but your solution is, instead of loadding by AJAX, just insert the script tag in your document:

// Instead of $.ajax(... /myScript.js) use:

function loadMyScript(){
        var script = document.createElement("script");
        script.type  = "text/javascript";
        script.src   = 'myScript.js';
        script.onload = function() {                           
            empModule.doSomething(); // or callback
        };
}

Upvotes: 0

Related Questions