0

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.

7
  • this.$scope.metaD = data; Commented Feb 9, 2015 at 14:56
  • 1
    why are you using this. everywhere? why this.$scope instead of $scope Commented Feb 9, 2015 at 15:03
  • @WayneEllery, why use $scope at all inside the service Commented Feb 9, 2015 at 15:19
  • @NewDev I think the OP only used $scope in the controller although it wasn't exactly clear Commented Feb 9, 2015 at 15:22
  • @WayneEllery, it seems pretty clear to me that it is inside a service definition Commented Feb 9, 2015 at 15:23

3 Answers 3

1

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;
      });
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot, that solved for me. And thank you for the advices and the tips about patterns, i'm gonna read more about it. I'm new at AngularJs!
1

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

2 Comments

Although this may address the OP's particular bug, your answer promotes incorrect separation of concerns with the use of $scope inside the service. That makes the service less re-usable, or at any rate, less-testable.
Yes, I agree with you. I try only to answer the specific question.
0

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.

2 Comments

.then here is completely useless - it doesn't do anything
Your right, the above example doesn't show the benefits but I generally use this technique to just return the response or pre-parse the data before returning. So the caller gets the processed data on their 'then' call.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.