0

I tried creating a service that will get data from a local JSON file, but it's not working, and there's no explanation why not.

The plunkr is here. Here's my code for the service:

webTestApp.factory('webtest', function($q, $timeout, $http) {
    var Webtest = {
        fetch: function(callback) {
            var ret = function() {
                $http.get('webtest.json').success(function(data) {
                    return data;
                });
            };

            return ret();
        }
    };
    return Webtest;
});

The Plunkr above is exactly what I was doing in my project, but I forked another Plunkr where someone got the same sort of thing was working. I found it at this StackOverflow answer.

Here's a working version

webTestApp.factory('webtest', function($q, $timeout, $http) {
    var Webtest = {
        fetch: function(callback) {

            var deferred = $q.defer();

            $timeout(function() {
                $http.get('webtest.json').success(function(data) {
                    deferred.resolve(data);
                });
            }, 30);

            return deferred.promise;
        }
    };

    return Webtest;
});

My question is, why does my version (the first block) not work, but the second one does?

1
  • 2
    because you are not returning the promise from the function: return $http.get.... Commented Nov 5, 2014 at 16:14

1 Answer 1

1

You are overcomplicating it with the ret function. Here is a simplified version of your code where I simply return the promise that $http call returns: http://plnkr.co/edit/9VaqIuOVHyMI12Z0r3jm?p=preview

To get your version to work, your ret function needs to return something ($http is an async call, so it doesn't matter its success actually callback returns something):

        var ret = function() {
            return $http.get('webtest.json').success(function(data) {
      // this ^^ is the key
                return data;
            });
        };

Then, when the $http promise is resolved, the actual data content is in response.data, not just response (full response actually contains headers and other server call-related info). Here is your original version with those two fixes: http://plnkr.co/edit/mzsdTFWr3qAXGfizjRRC?p=preview

That second example you wrote works because it return a simple $q promise (that's why $scope.data works and $scope.data.data is not needed), but it represents an antipattern, so you should stick with your original approach (or use the simplified version I gave you in the first paragraph).

Sign up to request clarification or add additional context in comments.

8 Comments

huh? So if I add return before $http.get... it should work? I tried, but it's still not working
As I said, two things to fix: return, and response.data (in your case $scope.data.data). It clearly works in my plunker: plnkr.co/edit/mzsdTFWr3qAXGfizjRRC?p=preview. Promise returned by an $http call is slightly different than a $q promise.
Ah so $http.get(..).success(function(..){..}); returns a response object, with a data object attached?
Sure. It's just a callback function and you can omit it from the service. then() call in the controller is enough. You'd use success (or then) in the service if you wanted to, say, modify data or something before returning it. See the service here, that's all you need in it: plnkr.co/edit/oKva09i1X0wepxgPCYP6?p=preview
Because it will return undefined. Remember, when we first call the $http function, it returns the promise RIGHT AWAY (much before it actually reaches the file it needs)! So, promise.data will be undefined and the scope variable will remain so while if we return the promise itself, the scope variable will get updated as soon as the promise is resolved or rejected.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.