Igor Santana
Igor Santana

Reputation: 143

Error in promises in AngularJS

I'm using a promise to get data from a json in my service and then passing it to my controller.I'm having some problems with this.

That's my Service

getMetaData: function () {
            var defer = this.$q.defer();
            this.$http.get('http://localhost:8084/login-api/public/metadata/describe/Coisa')
                    .success(function (data, status, headers, config) {
                        defer.resolve(data)
                    })
                    .error(function (data, status, headers, config) {
                        defer.reject(status);
                    })
            return defer.promise;

        }

And here i'm calling the Service im my controller

getData: function () {
            this.$scope.meta = this.EntityService.getMetaData();
            var dataS = {};
            this.$scope.meta.then(
                    function (data) {
                        this.$scope.metaD = data;
                    },
                    function (err) {
                        alert('Error');
                    }
            )
        }

And this is the error that I'm having:

TypeError: Cannot set property 'metaD' of undefined
at basic-list-controller.js:29
at l.promise.then.l (angular.js:7)
at angular.js:7
at u.$get.u.$eval (angular.js:7)
at u.$get.u.$digest (angular.js:7)
at u.$get.u.$apply (angular.js:7)
at p (angular.js:7)
at T (angular.js:7)
at XMLHttpRequest.b.onreadystatechange (angular.js:7)

And i can't see why i'm having this error. When i log the data on the console, it's there, but i can't give the value to a variable.

Upvotes: 0

Views: 64

Answers (3)

iQ.
iQ.

Reputation: 3953

You can simplify it to this because using a $http service can return a promise directly and use the 'then' function to pre-process data before returning it:

getMetaData: function () {
            return $http.get('http://localhost:8084/login-api/public/metadata/describe/Coisa')
                    .then(function (success) {
                        return success.data;
                    },
                      function (error) {
                        return error;
                    });
        }

This should now work with the rest of your code. Note I return the entire result, if you just want the response then return 'succes.data'. Or you can check for it on controller code.

Upvotes: 0

New Dev
New Dev

Reputation: 49590

There are a number of things wrong with how you approach this.

First: you don't need to use $q.defer for something that already returns a promise, like $http - this is considered a deferred anti-pattern.

Second: avoid passing $scope to your service - it makes it more difficult to test and upsets separation of concerns. $scope belongs to the controller.

And so, your service can be made much simpler. You don't even need two methods - since both return the same thing

.factory("myDataService", function($http){
    return {
       getMetaData: function(){
          return $http.get('url/to/data');
       }
    };
}


.controller("MainCtrl", function($scope, myDataService){
   myDataService.getMetaData()
      .then(function(data)){
         $scope.metaD = data;
      });
}

Upvotes: 1

Andrea Beggiato
Andrea Beggiato

Reputation: 164

In your success function "this" is not what you expect

function (data) {
    this.$scope.metaD = data;
}

You can try setting this outside your callback like this:

var _this = this;

and inside your callback use:

function (data) {
    this.$scope.metaD = data;
}

Your final code should look like:

getData: function () {
        var _this = this;
        this.$scope.meta = this.EntityService.getMetaData();
        var dataS = {};
        this.$scope.meta.then(
                function (data) {
                    _this.$scope.metaD = data;
                },
                function (err) {
                    alert('Error');
                }
        )
    }

Upvotes: 1

Related Questions