JavaScript AJAX Basics (retiring) Programming AJAX Stage 2 Challenge

Not working due to function scope problem...I think

My code looks like this:

  var xhrEmployees = new XMLHttpRequest();  
  var employees = document.getElementById("employeeList");

  xhrEmployees.onreadystatechange = function () {

    if (xhrEmployees.readyState === 4 && xhrEmployees.status === 200) {

      var employees = JSON.parse(xhrEmployees.responseText),
        statusHTML = '<ul class = "bulleted">',
        i;

      for (var i = 0; i < employees.length; i += 1) {
        if (employees[i].inoffice) {
          statusHTML += '<li class="in">';
        } else {
          statusHTML += '<li class="out">';
        }
        statusHTML += employees[i].name;
        statusHTML += '</li>';
      }

      statusHTML += '</ul>';
      employees.innerHTML = statusHTML;

    }
  };

  xhrEmployees.open("GET", "../data/employees.json");
  xhrEmployees.send();

This doesn't work, but if I move the line

var employees = document.getElementById("employeeList");

down above the line

employees.innerHTML = statusHTML;

it then works!

Working code:

  var xhrEmployees = new XMLHttpRequest();  

  xhrEmployees.onreadystatechange = function () {

    if (xhrEmployees.readyState === 4 && xhrEmployees.status === 200) {

      var employees = JSON.parse(xhrEmployees.responseText),
        statusHTML = '<ul class = "bulleted">',
        i;

      for (var i = 0; i < employees.length; i += 1) {
        if (employees[i].inoffice) {
          statusHTML += '<li class="in">';
        } else {
          statusHTML += '<li class="out">';
        }
        statusHTML += employees[i].name;
        statusHTML += '</li>';
      }

      statusHTML += '</ul>';
      var employees = document.getElementById("employeeList");
      employees.innerHTML = statusHTML;

    }
  };

  xhrEmployees.open("GET", "../data/employees.json");
  xhrEmployees.send();

I know it has something to do with scope, but I am confused - if the variable is global, can't all functions see it?!

Any help, as always, gratefully appreciated.

3 Answers

Jacob Mishkin
Jacob Mishkin
23,081 Points

One of the thing to look at(and could be wrong on this) is the use of the variable employees. You have two variables named this and it should be two different named variables. I believe this is the reason you might be having issues is the scope of the same named variable.

Hi Jacob

Thanks for the response, however that didn't fix the problem.

I altered my code so that there were 2 variable names:

  var xhrEmployees = new XMLHttpRequest(), // employees request object 
    xhrRooms = new XMLHttpRequest(),
    employeesDiv = document.getElementById("employeeList"); // rooms request object

  xhrEmployees.onreadystatechange = function () {

    if (xhrEmployees.readyState === 4 && xhrEmployees.status === 200) {

      var employees = JSON.parse(xhrEmployees.responseText),
        statusHTML = '<ul class = "bulleted">',
        i;

      for (i = 0; i < employees.length; i += 1) {
        if (employees[i].inoffice) {
          statusHTML += '<li class="in">';
        } else {
          statusHTML += '<li class="out">';
        }
        statusHTML += employees[i].name;
        statusHTML += '</li>';
      }

      statusHTML += '</ul>';
      employeesDiv.innerHTML = statusHTML;

    }
  };

  xhrEmployees.open("GET", "../data/employees.json");
  xhrEmployees.send();

Still doesn't work - it only works when you include the variable employeesDiv inside the 1st if function.

Maybe I need to revisit function scope, but I thought global variable were visible by all functions?

Where is your javaScript being linked in HTML? In your index.html, Try moving the link to your javaScript file from the head, down to the bottom, right above the closing body tag. Do this while keeping your employeesDiv variable in the global scope (do give your original two "employees" variables different names, this is a best practice, both for readability and code resiliency).

If javaScript is added at the top of your HTML, then your javaScript variable "employeesDiv" is being read before HTML has loaded the actual div. Therefore, JavaScript would be searching for nothing, return "null" and continue on its way. This, of course, would break your functions. I think it works when you move the variable into your AJAX callback because the AJAX callback is not being fired until after the HTML is done loading (so therefore, your variable has access to the div you are trying to get at it). I don't know if this is by design (AJAX only runs after HTML is done loading) or because HTML won the race with AJAX (JS loads, AJAX request goes out, HTML continues loading at the same time AJAX request goes out, HTML finishes loading, AJAX request comes back in, readyStatus changes, function runs, variable is able to access the div). Someone smarter than me please chime in here to say which it is.

Anyway, this is why it is always a best practice to include your javaScript link at the bottom of your HTML document, and not the head. It is crucial to do it this way especially you are using javaScript to access elements of the DOM (like we are doing here).