Gabriel Kunkel Gabriel Kunkel - 4 months ago 9
AngularJS Question

Can't access scope of value in then() despite arrow function

In this class for an angular component I'm having a scope issue that I don't understand.

class ConnectionsComponent {
constructor($http, $q) {
this.$http = $http;
this.$q = $q;
this.listGotten = [];
this.arrayOfGets = ['id1', 'id2', 'id3'];
}

$onInit() {
var promises = [];

angular.forEach(this.arrayOfGets, getThis => {
var promise = this.$http.get('/api/endpoint/' + getThis)
promises.push(promise)
}) // end angular.forEach

this.$q.all(promises).then((data) => {
this.listGotten = data;
console.log(this.listGotten) // <-- prints array of objects
})

console.log(this.listGotten) // <-- empty array (PROBLEM!)

} // end $oninit

} // end class


According to this post, it shouldn't be an issue because I'm using the arrow function which passes the scope into the
then()
. It's NOT
undefined
, it's just an empty array, as if
this.listGotten
never had
data
assigned to it.

Answer

It's a matter of timing. Your .then() handler is called LATER because it represent the completion of all your asynchronous operations. Whereas, your:

console.log(this.listGotten) // <-- empty array (PROBLEM!)  

is executed before your .then() handler has even run so this.listGotten has not yet been set. Your arrow functions are working as expected - this is not an issue related to that.

If you put some console.log() statements into your code to see the actual timing of things like this:

  $onInit() {
    var promises = [];
    console.log("1 - start");   
    angular.forEach(this.arrayOfGets, getThis => {
      var promise = this.$http.get('/api/endpoint/' + getThis)
      promises.push(promise)
    }) // end angular.forEach

    console.log("2 - about to do .all()");
    this.$q.all(promises).then((data) => {
      console.log("3 - inside .then() handler");
      this.listGotten = data;
      console.log(this.listGotten) // <-- prints array of objects
    })

      console.log("4 - after .then() handler");
      console.log(this.listGotten) // <-- empty array (PROBLEM!)    

  } // end $oninit

Then, you will see this output:

1 - start
2 - about to do .all()
4 - after .then() handler
3 - inside .then() handler

So, you can see that your .then() handler is called after your other console.log() executes.

The solution for asynchronous results is to "use them in the callback where they are presented" because that's the ONLY place you know the timing for when they exist.

Remember in asynchronous code, all your $http.get() operations just initiate the http requests and then they run in the background. The rest of your Javascript continues to run and some time LATER your asynchronous requests will finish and call their callbacks, long after the rest of your code has finished executing.