简体   繁体   中英

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.

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');
                }
        )
    }

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;
      });
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM