2

I am trying to return data from $http.then function:

if(navigator.onLine){
    $http({
      method:'GET',
      url:url,
    }).success(function(data, status){
         localStorage.setItem('abc', JSON.stringify(data));
    }).then(function(){
      return JSON.parse(localStorage.getItem('abc'));   
    });
  }else{
    return JSON.parse(localStorage.getItem('abc')); 
  }

I am able to get the Json data from the else block but getting null value from the then function.

And this function is inside a service.

kryger
  • 12,906
  • 8
  • 44
  • 65
Anenth
  • 674
  • 8
  • 24

2 Answers2

5

You cannot return the response from an asynchronous call. You need to return the promise for it, i.e. the result of the .then method.

Likewise, you want to return an (already fulfilled) promise for the data from the DOM storage as well.

if (navigator.onLine){
    return $http({
        method:'GET',
        url:url
    }).then(function(response) {
        localStorage.setItem('abc', JSON.stringify(response.data));
        return response.data;
    });
} else {
    return $q.when( JSON.parse(localStorage.getItem('abc')) );
}
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • when i consoled the return, i am getting `Object {data: Object, status: 200, headers: function, config: Object}` – Anenth Sep 26 '13 at 14:01
  • @Anenth: Ah, sounds reasonable. Unlike the `success` callback multiple parameters, the `$http` promise yields an object, of which we are only interested in the `.data` property. Adjusted my answer. – Bergi Sep 26 '13 at 14:10
  • why do we have to return the $http object ? and it does work without the return statement in the then block – Anenth Sep 26 '13 at 14:31
  • 1
    It doesn't return the `$http` function, but the *Promise* it returns for the results (and actually not even that directly, since we transform the result with `then` and return another promise). The point of promises is that their callbacks will happen in the future (ajax is asynchronous! You can't `return` from callbacks), but you can chain transformations and pass promises around when the code is executing. – Bergi Sep 26 '13 at 14:43
0

If you want to do some processing before 'returning' you could create another promise using $q, it would go something like this:

var defer = $q.defer();
if(navigator.onLine){
  $http({
    method:'GET',
    url:url,
  }).success(function(data, status){
     localStorage.setItem('abc', JSON.stringify(data));
  }).then(function(){
    defer.resolve(JSON.parse(localStorage.getItem('abc')));   
  });
}else{
  defer.resolve(JSON.parse(localStorage.getItem('abc'))); 
}
return defer.promise;

what this does is that even if you have a $http call or not, you will be returning a consistent type, no longer worrying whether you need to wait or not.

In your caller you will do something like this (say the above code belongs to a method foo):

foo().then(function (data) {
  // here data contains your returned JSON parsed object
}
Mutahhir
  • 3,812
  • 3
  • 21
  • 26
  • 1
    No! Don't do this. No need for another `$q.defer()` when you can use `.then()`. This solution is actually quite wrong because it does not handle errors. – Bergi Sep 26 '13 at 13:48
  • thanks, it works but i didnt understand is when i consoled returned value i am getting `Object {then: function, catch: function, finally: function}` but the data is correctly displayed within ng-repeat – Anenth Sep 26 '13 at 13:52
  • @Bergi, I agree it isn't complete, but you could definitely handle that using defere.reject(err) etc. However, I think I'll agree that your solution is simpler. This makes more sense to me in my head though that's all. :) – Mutahhir Sep 27 '13 at 03:52
  • @Anenth, the return value *is* and object that contains methods, most importantly, like `then` which you just have to call on the returned object and pass it a `function`. That function will be called when the "promise" is fulfilled. – Mutahhir Sep 27 '13 at 03:56