Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scoping within Angular service call

I'm confused as to why I cannot get this service call to perform as needed. The console.log's within definitionsService.get promise resolution are what I would expect (the object I'm aiming to return). However the console.log right before I return defs is undefined which, of course, means my returned value is undefined. What am I missing?

function getDefinitions() {
  var defs;
  definitionsService.get().$promise.then(function(data) {
    console.log(data);
    defs = data;
    console.log(defs);
  });
  console.log(defs);
  return defs;
};

I changed the above to:

function getDefinitions() {
  var defs = $q.defer();
  definitionsService.get().$promise.then(function(data) {
    defs.resovle(data);
  });
  return defs.promise;
};

per the below answer.

I also changed the way I call this method per the same answer like this:

function detail(account) {
  getDefinitions().then(function(definitions) {
    var key = angular.isDefined(definitions.ABC[account.code]) ? account.code : '-';
    return definitions.ABC[key].detail;
  });
}

Then in my controller I'm trying to do the following:

var getAccounts = function() {
  playersService.getAccounts({
    playerId: playerId
  }).$promise.then(function(accounts) {
    for (var i = 0; i < accounts.length; i++) {
      accounts[i].detail = utilitiesService.detail(accounts[i]);
    }
    vm.accounts = accounts;
  });
};

var init = function() {
  getAccounts();
};

init();

My problem is that accounts[i].detail is consistently undefined.

like image 264
MattDionis Avatar asked Oct 31 '22 22:10

MattDionis


1 Answers

Welcome to the world of asynchronous calls.

If you are making an async call inside getDefinitions (from definitonsService), then you must assume getDefinitions() is async as well. Which means you cannot simply return defs.

When you print defs before returning it, the async call of the service has yet to have been carried out.

defs should also be a promise object. You can then return it as you do, but the method invoking it should also use it with .then(function(defs)...

Or in code form:

function getDefinitions() {
  var defs = $q.defer();
  definitionsService.get().$promise.then(function(data) {
    defs.resovle(data);
  });
  return defs.promise;
};

And whoever calls getDefinitions() :

getDefinitions().then(function(defs) {
 // do something with defs...
}

Answer to question after edit:

The problem is once again with the async nature inside the getAccounts method. utilitiesService.detail is an async method. So you are in fact assigning promises, not values, to accounts[i].detail.

Since each account will entail an async call, using $q.all seems like a good idea:

var promises = [];
for (var i = 0; i < accounts.length; i++) {
      promises.push(utilitiesService.detail(accounts[i]));
    }
$q.all(promises).then(function(values)){
 // you should have all the account details inside 'values' and can update vm.accounts
}

remember - getting the promise is synchronous. Getting the value that the promise... well, promises to get you - that's asynchronous.

like image 186
Tom Teman Avatar answered Nov 11 '22 06:11

Tom Teman