0

I have the following script:

    <script>
                var xmlhttp = new XMLHttpRequest();
                var myApp = angular.module("myApp", []);

                xmlhttp.onreadystatechange = function () {
                    if (this.readyState == 4 && this.status == 200) {
                        response = this.responseText;
                        var myObj = JSON.parse(response);
                        console.log(myObj);

                    }
                };

                xmlhttp.open("GET", "functions.php?action=getuserdata&id=" + document.getElementById('userID').innerHTML, true);
                xmlhttp.send();

                console.log(myObj);

                myApp.controller("myCtrl", function ($scope) {
                    $scope.firstName = myObj[0].firstname;
                    $scope.lastName = myObj[0].lastname;
                    $scope.email = myObj[0].email;
                    $scope.cell = myObj[0].cell;
                    $scope.domainname = myObj[0].domainname;
                    $scope.tfamethod = myObj[0].tfamethod;
                    $scope.said = myObj[0].said;
                });
    </script>

Now my understanding is that the 'var' keyword, assigns a variable globally which is accessible from anywhere within the window. I set the var within the onreadystatechange function, and I'm able to see it when doing the first console.log, but I get it as 'undefined' when I log it again outside the function. Is my understanding of var incorrect? If so, how do I fix the code to be able to access myObj from outside the function?

anitag95
  • 307
  • 2
  • 16
  • Have a look here: https://www.w3schools.com/js/js_hoisting.asp, myObj is only valid in the callback function. – kangaro0 Sep 11 '17 at 07:21

4 Answers4

3

Two issues with that code:

var

Now my understanding is that the 'var' keyword, assigns a variable globally which is accessible from anywhere within the window.

That understanding is incorrect. var declares a variable within the function where var appears. To declare a global variable, declare it outside of all functions.

Or better yet, don't. The global namespace on browsers is very crowded. Instead, wrap all of your code in a scoping function and put your "globals" there. They'll be accessible to all of your code, without actually being global.

Timing

Separately: You can't use myObj where you had it in your code, because it won't have been assigned yet, regardless of where it's declared. See this question's answers for why.


So here's that code with a scoping function, and using myObj in the correct place (inside the callback); also, since you only ever use the first entry in the returned array, you could access that entry once instead of repeatedly:

(function() {
    var xmlhttp = new XMLHttpRequest();
    var myApp = angular.module("myApp", []);

    xmlhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            response = this.responseText;
            var myObj = JSON.parse(response)[0];           // Note the [0]
            myApp.controller("myCtrl", function($scope) {
                $scope.firstName = myObj.firstname;
                $scope.lastName = myObj.lastname;
                $scope.email = myObj.email;
                $scope.cell = myObj.cell;
                $scope.domainname = myObj.domainname;
                $scope.tfamethod = myObj.tfamethod;
                $scope.said = myObj.said;
            });
        }
    };

    xmlhttp.open("GET", "functions.php?action=getuserdata&id=" + document.getElementById('userID').innerHTML, true);
    xmlhttp.send();
})();
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

The scope of a variable declared with var is its current execution context, which is either the enclosing function or, for variables declared outside any function, global.

Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var

So if you declare a variable inside a function, it is not accessible outside this function.

Fixed code:

var myObj;
xmlhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        response = this.responseText;
        myObj = JSON.parse(response);
        console.log(myObj);

    }
};

xmlhttp.open("GET", "functions.php?action=getuserdata&id=" + document.getElementById('userID').innerHTML, true);
xmlhttp.send();

console.log(myObj);
JSON Derulo
  • 9,780
  • 7
  • 39
  • 56
0

variables defined with var have functional context. They are first hoisted on top of function and available only from function body. If you want to access variable from outside first define it outside and access inside the function. Only Variables which are used without being defined has global scope.

Nikhil Ranjan
  • 994
  • 12
  • 16
0

I think you need to understand how variable scope works. MDN does a great job explaining it

But long story short. If you want to create a 'global' variable which is bad, It would have be to in the same block as your second console.log()

So this bit of code would be refactored to.

//Global variable
var myObj;
xmlhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
   response = this.responseText;
   myObj = JSON.parse(response);
   console.log(myObj);

    }
};

xmlhttp.open("GET", "functions.php?action=getuserdata&id=" + document.getElementById('userID').innerHTML, true);
            xmlhttp.send();
// Probably will log incorrectly because of the timing, 
// This code is ran before the callback of the XHR, because the
// javascript interpreter wont wait for that callback to finish before 
// interpreting additional code (Which is good cause then the UI 
// doesn't pause while the request is being performed 
 console.log(myObj); 

I will give you another example

  var foo = 1;
    function log(){
       var bar = 2
       baz = 4
       console.log(foo); // 1
       console.log(bar) // 2
       console.log(baz) // 3
    }


   console.log(foo); // 1
   console.log(bar) // undefined
   console.log(baz) // 3

Also I have noticed you are using angularJS, yet you are writing super verbose XHR requests, I would recommend you to check out the HTTP service.

realappie
  • 4,656
  • 2
  • 29
  • 38