Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have an Angular app with a service and a contoller:

service.js

.factory('MyService', function ($http, $q) {
    var api_url = 'http://localhost/api/';

    var MyService = {

        list: function (items_url) {
            var defer = $q.defer();
            $http({method: 'GET', 
                url: api_url + items_url}).
                success(function (data, status, headers, config) {
                    defer.resolve(data);
                }).error(function (data, status, headers, config) {
                    defer.reject(status);
                });
            return defer.promise;
        },
        ...
   }
});

controller.js

.controller("ItemsCtrl", function ($scope, MyService) {

    $scope.getItems = function () {
        MyService.list('items/').then(function(data) {
            $scope.items = data;
        });
    };

    $scope.addItems = function () {
        $scope.getItems();

        // why is this undefined ??!!!
        console.log($scope.items); 
    };

The issue is that I want to call the $scope.getItems method inside the $scope.addItems method. Do I perhaps need to use $scope.apply(), as the returned value is a promise?

I think what I am displaying here is a general lack of understanding :/

Any help would be much appreciated.

share|improve this question
add comment

3 Answers

up vote 1 down vote accepted

Change your controller like this:

.controller("ItemsCtrl", function ($scope, MyService) {

    $scope.getItems = function () {
        return MyService.list('items/').then(function(data) {
            $scope.items = data;
        });
    };

    $scope.addItems = function () {
        $scope.getItems().then(function() {

          // should be what you want this time
          console.log($scope.items); 

        });
    };

Your problem is when you call $scope.getItems(), http response is not returned yet, so $scope.items is not populated. You have to wait for all the promises are resolve to access items.

share|improve this answer
add comment

$scope.items is undefined because $http is an asynchronous communication. That is, when you call $scope.addItems(), it creates and sends the request to retrieve your list of items, then immediately moves on to the next line of code, which is to log $scope.items to the console. Since there's nothing in $scope.items yet, you get an undefined value.

If you want to operate on the data returned by the http call, you must guarantee that the data will be populated. In other words, any operations you want to perform on $scope.items should be called within your .then() block.

$scope.$apply() is used when you are not executing within an AngularJS context, to force the AngularJS framework to evaluate the expression. It will not help you here - you'll get an "$digest already in progress" error, or something along those lines.

Try this:

.controller("ItemsCtrl", function ($scope, MyService) {

  $scope.getItems = function () {
    MyService.list('items/').then(function(data) {
      $scope.items = data;
      console.log($scope.items); 
    });
  };

  $scope.addItems = function () {
    $scope.getItems();
  };
});
share|improve this answer
add comment

That is because $scope.getItems is asynchronous. Your callback (that added via then) is called after $scope.addItems executed.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.