d4rty d4rty - 2 months ago 8
AngularJS Question

AngularJS - TypeError while accessing JS object name/value pair of an service object

Why is the expression

databaseService[user1Constant].accountBalance
producing the error below?

angularJsApplicationController.js
:

app.controller("angularJsController", function ($scope, $location, $http, user1Constant, user2Constant, databaseService) {
databaseService[user1Constant+'Request'].done(function(){
console.log(JSON.stringify(databaseService));
console.log(user1Constant);
console.log(databaseService);
console.log(databaseService[user1Constant]);
console.log(databaseService[user1Constant].accountBalance);
});
});


enter image description here




This is the code where I create the object:
angularJsApplication.js
:

app.service("databaseService", ["user1Constant","user2Constant", function (user1Constant, user2Constant) {
var returnObject = {};
returnObject.updateAllEntriesUser = function (user) {

//jQuery AJAX HTTP method
$.post("getEntriesFromUser.php", {
user: user
})
.done(function (response) {
response = JSON.parse(response);
returnObject[user]={};
returnObject[user].bookings = response;
var totalAmount = 0;
for (var i = 0; i < response.length; i++) {
totalAmount += parseFloat(response[i].amount_before_comma + '.' + response[i].amount_after_comma);
}
returnObject[user].accountBalance = totalAmount;
});
};
returnObject[user1Constant + 'Request'] = returnObject.updateAllEntriesUser(user1Constant);
returnObject[user1Constant + 'Request'] = returnObject.updateAllEntriesUser(user2Constant);
return returnObject;
}]);

Answer

The console is showing you the object state as it is currently after the request is complete, which isn't what it looks like when you write it to the console. Your controller is trying to access the data before it's loaded, which is why your user data doesn't have the properties you expect it to.

You need to return a jQuery deferred object from your service and then pass a function to its done function so that you can wait to get the data until it's loaded.

Or you could cheat and use $scope.$watch...

You could change it to be more flexible, but to get it to work with the least amount of changes:

app.service("databaseService", ["user1Constant","user2Constant", function (user1Constant, user2Constant) {
  var returnObject = {};
  returnObject.updateAllEntriesUser = function (user) {

    //jQuery AJAX HTTP method
    return $.post("getEntriesFromUser.php", {
        user: user
    })
        .done(function (response) {            
            response = JSON.parse(response);
            returnObject[user]={};
            returnObject[user].bookings = response;
            var totalAmount = 0;
            for (var i = 0; i < response.length; i++) {
                totalAmount += parseFloat(response[i].amount_before_comma + '.' + response[i].amount_after_comma);
            }
            returnObject[user].accountBalance = totalAmount;
        });
  }

  returnObject[user1Constant + 'Request'] = returnObject.updateAllEntriesUser(user1Constant);
  returnObject[user2Constant + 'Request'] = returnObject.updateAllEntriesUser(user2Constant);
  console.log(returnObject); //angularJsApplication.js:101
  return returnObject;
});

And your controller:

app.controller("angularJsController", function ($scope, $location, $http, user1Constant, user2Constant, databaseService) {
    databaseService[user1Constant + 'Request'].done(function() {
        /* Now I can get databaseService[user1Constant] */
    });
});