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?

Community
  • 1
  • 1
CodyBugstein
  • 21,984
  • 61
  • 207
  • 363

1 Answers1

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).

Community
  • 1
  • 1
Shomz
  • 37,421
  • 4
  • 57
  • 85
  • huh? So if I add `return` before `$http.get...` it should work? I tried, but it's still not working – CodyBugstein Nov 05 '14 at 17:16
  • As I said, two things to fix: `return`, and `response.data` (in your case `$scope.data.data`). It clearly works in my plunker: http://plnkr.co/edit/mzsdTFWr3qAXGfizjRRC?p=preview. Promise returned by an $http call is slightly different than a $q promise. – Shomz Nov 05 '14 at 17:20
  • Ah so `$http.get(..).success(function(..){..});` returns a response object, with a data object attached? – CodyBugstein Nov 05 '14 at 19:22
  • Exactly! Actually, the success function makes no difference, $http.get() does all the work. – Shomz Nov 05 '14 at 19:30
  • I don't understand what you mean when you say "the success function makes no difference". Can you explain? – CodyBugstein Nov 05 '14 at 19:46
  • 1
    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: http://plnkr.co/edit/oKva09i1X0wepxgPCYP6?p=preview – Shomz Nov 05 '14 at 19:52
  • Can I ask one more question? Why doesn't it work if I change the controller code to `$scope.data = webtest.fetch().data;`? – CodyBugstein Nov 05 '14 at 20:01
  • 1
    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. – Shomz Nov 05 '14 at 20:06