0

I'm a little confused as to why this isn't working. I'm guessing it's a scope issue but not entirely sure.

I get values pushed to myProjectIds if I log inside the function. But outside I cannot figure out why the global array declared at the top is empty.

Appreciate any help!

var myProjects = [];
var myProjectIds = [];

function getProjects() {
  $.ajax({
    method: 'GET',
    url: 'http://localhost:8080/project',
    data: {
      user: userId,
    },

    // dataType: "json",
    beforeSend: function (xhr) {
      /* Authorization header */
      xhr.setRequestHeader("Authorization", "Bearer " + userToken);
    },
    success: function (response) {
      myProjects = response;
      for (var i = 0; i < myProjects.projects.length; i++) {
        myProjectIds.push(myProjects.projects[i]._id);
      }
    }
  })
}

getProjects();
console.log(myProjectIds)
  • This has nothing to do with scope and everything to do with asynchronous processing. You only have values inside of the `success` or *after* it is finished (which is not, generally speaking, the next line after calling the function). You need to pass a callback to process the data or work with promises and/or async/await. – crashmstr Dec 10 '20 at 17:24
  • you don't need to assign `response` to `myProjects`, you may simply loop through it (like, `for(..; response.length..`, furthermore, your loop would have a bit more neat appearance with `for({id} of response) myProjectIds.push(id)` (or with `.forEach()`-loop) – Yevhen Horbunkov Dec 10 '20 at 17:27

1 Answers1

0

This is because your ajax call here is asynchronous - The browser is still waiting for the response of the network request when it runs your console log. If you want to see this behaviour, put your log in a loop:

var myProjects = [];
var myProjectIds = [];

function getProjects() {
  $.ajax({
    method: 'GET',
    url: 'http://localhost:8080/project',
    data: {
      user: userId,
    },

    // dataType: "json",
    beforeSend: function (xhr) {
      /* Authorization header */
      xhr.setRequestHeader("Authorization", "Bearer " + userToken);
    },
    success: function (response) {
      myProjects = response;
      for (var i = 0; i < myProjects.projects.length; i++) {
        myProjectIds.push(myProjects.projects[i]._id);
      }
    }
  })
}

getProjects();
setInterval(function() {
    // When the network call returns, this will log a non empty array
    console.log(myProjectIds)
}, 100)

If you want to make this a bit easier to use you can use a promise to return the result of the call.

Here's an example with your code in a promise:

function getProjects() {
  return new Promise((resolve, reject) => {
      $.ajax({
        method: 'GET',
        url: 'http://localhost:8080/project',
        data: {
          user: userId,
        },
        beforeSend: function (xhr) {
          xhr.setRequestHeader("Authorization", "Bearer " + userToken);
        },
        success: function (response) {
          // This is a cleaner way of writing the for loop
          const myProjectIds = response.projects
               .map((project) => project._id);
          resolve(myProjectIds);
        }
      })
    }
  }
}

getProjects().then((projectIds) => {
    // Do something with the result
    console.log(projectIds)
})
James Paterson
  • 2,652
  • 3
  • 27
  • 40