Tulun Tulun - 26 days ago 7
Javascript Question

$scope variable from api call sometimes doesn't update

So I am trying to display some data after a user successfully logs into an external API.

When I login, sometimes the data doesn't update properly until I refresh the page; In addition, this bug seems to only persist after a full refresh AND I have logged out of the API.

the service is like this:

angular.module('myApp')
.service('PlayerAPICall', function ($http, $q) {
// AngularJS will instantiate a singleton by calling "new" on this function
var deferred = $q.defer();

return {
getPlayerInfo: function() {
var getPlayerBasic = {
method: 'GET',
url: 'API_URL',
headers: {
'Accept': 'HEADER'
}
};

// This API call returns some basic player information for the current logged in user.
$http(getPlayerBasic).success(function(response) {
deferred.resolve(response);
});

return deferred.promise;
},
}
});


My directive for this is like this (With the pertinent information)

angular.module('myApp')
.controller('NavbarCtrl', function($scope, PlayerAPICall) {

// Declare $scope objects.
$scope.playerBasic;

PlayerAPICall.getPlayerInfo().then(function(response) {
$scope.playerBasic = response;
});

})


The partial looks like this:

<div class='links-container'>
<div class='row'>
<div class='inputs'>
<form ng-submit='submit()'>
<p ng-show='playerBasic.first_name != null' class='md-text logout-container'>
Hello, {{playerBasic.first_name}}
<span class='logout-span'><button class='btn btn-primary logout-btn' type='submit' ng-model='submit'>Logout</button></span></p>
<p ng-show='playerBasic.first_name == null' class='md-text logout-container'>
Hello, {{playerBasic.email}}
<span class='logout-span'><button class='btn btn-primary logout-btn' type='submit' ng-model='submit'>Logout</button></span>
</p>
</form>
</div>
</div>


Although I KNOW the name variable exists for this user, it sometimes says:

'Hello, '
Instead of 'Hello, name'.

I'm not entirely sure why the $scope doesn't change.

Answer

There is no need to manufacture a promise with $q.defer() as the $http service already returns a promise:

angular.module('myApp')
  .service('PlayerAPICall', function ($http, $q) {
    //var deferred = $q.defer();

    return {
      getPlayerInfo: function() {
        var getPlayerBasic = {
          method: 'GET',
          url: 'API_URL',
          headers: {
            'Accept': 'HEADER'
          } 
        };

        //$http(getPlayerBasic).success(function(response) {
        //  deferred.resolve(response);
        //});
        //return deferred.promise;

        var promise = $http(getPlayerBasic);
        var derivedPromise = promise.then(function(response) {
            //return data to chain
            return response.data;
        }); 
        return derivedPromise;
      },
    }

});

The above example creates a promise that resolves with the data property of the response object if successful. Errors are rejected with the response object of the erroneous response.

The advantage of deriving promises this way is that the promise chain is not broken if there is an error. Failure to provide a rejection to $q.defer() will cause the $q.defer promise to hang when there are errors and will create memory leaks.