javascript – Scope of variables inside $.getJSON

Question:

The role variable receives a new value in each Loop , when it is inside $.getJSON it takes the second value from the array and doesn't change anymore. There are two console.log(); in the code, I put their return next to it. Does anyone know the cause of this and how to get rid of this undesirable scenario?

$(document).ready(function() {
  var emails = ["phellipelins@gmail.com", "phellipelins@gmail.com"],
    TeamRole = ["founder", "manager"],
    hashMail;

  for (var i=0 ; i < emails.length ; i++){ 
    hashMail = "http://www.gravatar.com/" + md5(emails[i].toLowerCase().trim()) + ".json?callback=?";
    role = TeamRole[i];
    console.log(role); // > founder > manager

    $.getJSON(hashMail, function (data) {
      console.log(role); // > manager > manager
      $("#profile-container").append(
            "<div>" +
                "<img src='" + data.entry[0].thumbnailUrl + "?s=200>" +
                "<p>" + data.entry[0].displayName + "</p>" +
                "<p>" + self.role + "</p>" +
                "<p>" + data.entry[0].aboutMe + "</p>" +
            "</div>";
      );
    });
  };
});

Answer:

The problem is that getJSON is asynchronous. When the callback executes, the loop has ended. The scope of your variables is the function that contains them (in this case, the document.ready callback ), not the loop block. One solution is to introduce a new function, executed immediately, capturing each value of the role variable separately:

for (var i=0 ; i < emails.length ; i++){ 
  hashMail = "http://www.gravatar.com/" + md5(emails[i].toLowerCase().trim()) + ".json?callback=?";
  var role = TeamRole[i];
  console.log(role); // > founder > manager
  (function(role) {
      $.getJSON(hashMail, function (data) {
        console.log(role); // > manager > manager
        $("#profile-container").append(
              "<div>" +
                  "<img src='" + data.entry[0].thumbnailUrl + "?s=200>" +
                  "<p>" + data.entry[0].displayName + "</p>" +
                  "<p>" + role + "</p>" +
                  "<p>" + data.entry[0].aboutMe + "</p>" +
              "</div>";
        );
      });
  }(role));
};

Note: I added var to declare your role variable as it was going global.

Scroll to Top