AfterWorkGuinness
AfterWorkGuinness

Reputation: 1850

Angular promises - cannot read property then of undefined

I'm trying to display the result of a promise in the view, but I get this exception. Other cases of this exception I've found on Google / SO are caused by mistakes I don't see in my code.

I've verified I am using promises, I am resolving the promise inside of the function passed to $timeout, I am returning the promise from the function getData() and not the function that resolves the promise.

Thanks in advance.

Viewer

<html ng-app="controller" ng-controller="MyController as controller">
<head>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.16/angular.min.js"></script>
  <script type="text/javascript" src="controller.js"></script>
  <script type="text/javascript" src="services.js"></script>
</head>
<body>
  {{data}}
</body>
</html>

Controller (controller.js)

   angular.module('controller', ['services'])
    .controller('MyController', ['MyService', function(MyService) {

      MyService.getData().then(function(data) {
        $scope.data = data;
      });
    }]);

Service (services.js)

angular.module('services', [])
.factory('MyService', function($q, $timeout){
  var getData = function getData() {

    var deferred = $q.defer;

    $timeout(function () {
      deferred.resolve('Foo');
    }, 5000);

    return deferred.promise;
  };

  return {
    getData: getData
  };
});

Exception stack trace

TypeError: Cannot read property 'then' of undefined
    at new <anonymous> (controller.js:5)
    at Object.e [as invoke] (angular.js:4219)
    at $get.x.instance (angular.js:8525)
    at angular.js:7771
    at q (angular.js:334)
    at M (angular.js:7770)
    at g (angular.js:7149)
    at angular.js:7028
    at angular.js:1460

Upvotes: 1

Views: 8116

Answers (1)

PSL
PSL

Reputation: 123739

You are not getting deferred object properly, instead deferred variable holds the function reference, you missed invocation of defer constructor.

var deferred = $q.defer();
                        ^___Missing this

also note that you could just return $timeout as is, since it returns a promise. In your real case if you are using $http just return $http promise instead of creating a redundant promise object with deferred pattern.

.factory('MyService', function($q, $timeout){
  var getData = function getData() {

    return $timeout(function () {
        return 'Foo' ;
    }, 5000);
  };

  return {
    getData: getData
  };

Upvotes: 7

Related Questions