2

I'm attempting to call a service from within another service, then use the returned object to perform some operations. I keep running into a TypeError: getDefinitions is not a function error, however.

Below is my service is called, the service doing the calling, and my relevant controller code:

definitions.service.js:

'use strict';

angular.module('gameApp')
  .factory('definitionsService', ['$resource',
    function($resource) {
      var base = '/api/definitions';
      return $resource(base, {}, {
        get: {method: 'GET', url: base}
      });
    }]);

utilities.service.js:

'use strict';

angular.module('gameApp')
  .factory('utilitiesService', ['definitionsService',   function(definitionsService) {

    return {
      description: description,
      detail: detail,
      severity: severity,
    };

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

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

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

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

controller.js:

'use strict';

angular.module('gameApp')
  .controller('AccountsController', AccountsController);

AccountsController.$inject = ['$routeParams', 'customersService', 'utilitiesService'];

function AccountsController($routeParams, playersService, utilitiesService) {
  var vm = this;
  var playerId = $routeParams.playerId;

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

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

  init();
}
2
  • What happens if you change var getDefinitions = function() to function getDefinitions()? Commented Jul 30, 2015 at 13:19
  • @Guinn, progress! Now I get a new error: TypeError: Cannot read property 'ABC' of undefined which is odd because when I console.log(data) within the service call I can clearly see the IDV object within the data object. Commented Jul 30, 2015 at 13:43

2 Answers 2

3

Currently your service returns before your variable gets defined. That means the definition is never reached. So it is declared, as the function executes, but is undefined. Just move your variable definition to the top. This will only prevent the definition error. Another problem is that your getDefinitions function doesn't return anything but you're calling a property on it. One solution I can think of is using a callback, that gets executed when your data is loaded:

angular.module('gameApp')
  .factory('utilitiesService', ['definitionsService',   function(definitionsService) {
    var data;
    reload();
    var utils = {
      description: description,
      detail: detail,
      severity: severity,
      reload: reload,
      loaded: null
    };
    return utils;        

    function reload() {
       definitionsService.get().$promise.then(function(data) {
         data = data;
         if (utils.loaded && typeof utils.loaded === "function") {
           utils.loaded();
         }
       });
    }    

    function description(account) {
      var key = angular.isDefined(data.ABC[account.code]) ? account.code : '-';
      return data.IDV[key].description;
    }
}]);

Then in your controller you could use the service like this:

utilitiesService.loaded(function(){
    accounts[i].description = utilitiesService.description(accounts[i]);
})
Sign up to request clarification or add additional context in comments.

5 Comments

might prevent the definition error but none of those functions will work as OP expects
Actually the variable is declared through hoisting but it never gets assigned.
Thank you, that helped me solve the initial error, but you are correct, now I get TypeError: Cannot read property 'ABC' of undefined. Trying to workout how to code this properly so the object I'm looking for is actually returned.
@skubski thats what I wrote. 'So it is declared, as the function executes, but is undefined.' Well I used the term 'defined' instead of 'assigned', but that shouldnt matter.
Actually it was "The definition is never reached" that left me with the feeling there was a some ambiguity. And no, it doesn't matter.
0

old question but still relevant. To expand on Florian Gl's answer above if you have a service with multiple functions and one or more of those functions requires a "pre-service" function to be called for example to load some resource data in like configuration information move that service call to the top, outside of the nested function (in this case below I am dealing with the promise scenario in JavaScript):

    angular.module('gameApp')
      .factory('utilitiesService', ['definitionsService',   function(definitionsService) {

        var myFirstConfigValue = '';

        // call any all services here, set the variables first
        configurationService.GetConfigValue('FirstConfg')
           .then(function (response) {
                // set the local scope variable here
                myFirstConfigValue = response;
           },
           function() { });

        function myTestFunction() {
            // make an ajax call or something
            // use the locally set variable here
            ajaxService.functionOneTwo(myFirstConfigValue)
               .then(response) {
                    // handle the response
               },
               function(err) {
                  // do something with the error
                });

        }
    }]);

Key point to note here is that if you need to load in some data you do that first outside of any other functions inside your service (e.g. you want to load some JSON data).

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.