10

i have problems when it comes to $http promises in angularjs. i am doing this in my service: (the getSomething function should chain two promises)

the second function uses a external callback function!

app.service('blubb', function($http, $q) {

  var self = this;

  this.getSomething = function(uri, data) {
    return self.getData(uri).then(function(data2) {
      return self.compactData(uri, data2);
    });
  };

  this.getData = function(uri) {
    var deferred = $q.defer();
    $http.get(uri).success(function(data) {
      deferred.resolve(data);
    }).error(function() {
      deferred.reject();
    });

    return deferred.promise;
  };

  this.compactData = function(uri, data) {
    var deferred = $q.defer();
    /* callback function */
      if(!err) {
        console.log(compacted);
        deferred.resolve(compacted);
      } else {
        console.log(err);
        deferred.reject(err);
      }
    /* end of function */

    return deferred.promise;
  };
});

when i use the service in my controller it doesn't output the console.log:

blubb.getSomething(uri, input).then(function(data) {
  console.log(data)
});

edit: if i define the callback function by myself in 'compactData' it works, but i am using "jsonld.compact" from https://raw.github.com/digitalbazaar/jsonld.js/master/js/jsonld.js and THIS doesn't work!

    jsonld.compact(input, context, function(err, compacted) {
      if(!err) {
        console.log(compacted);
        deferred.resolve(compacted);
      } else {
        deferred.reject('JSON-LD compacting');
      }
    });

i am getting the console.log output in jsonld.compact but the resolve doesn't work and i don't know why..

it only works with $rootScope.$apply(deferred.resolve(compacted));

John Slegers
  • 45,213
  • 22
  • 199
  • 169
Betty St
  • 2,741
  • 21
  • 33
  • Unless `compacted` is defined somewhere and is in scope, then you probably want to change `deferred.resolve(compacted);` to `deferred.resolve("compacted");`, and probably the same for `err`. – Beetroot-Beetroot May 08 '13 at 09:39
  • sry, `compacted` and `err` are defined by the callback function! there is also the right output from `console.log(compacted)` in this function, but not in the 'chained' getSomething function. – Betty St May 08 '13 at 09:46
  • If it still doesn't work, then test `blubb.getData()` and `blubb.compactData()` separately before testing `blubb.getSomething()`. – Beetroot-Beetroot May 08 '13 at 10:05
  • i used `$rootScope.$apply` and it works! (see http://stackoverflow.com/questions/14529354/angularjs-promises-not-firing-when-returned-from-a-service?rq=1) BUT i am getting this error: `Error: $digest already in progress` – Betty St May 08 '13 at 10:17
  • 1
    Kindly share complete fiddle because there are so many things not given in the question – Ajay Beniwal May 08 '13 at 11:13
  • To avoid getting that $digest error try this: `if(!$scope.$$phase) { $scope.$apply(); }` – Renaud Oct 09 '13 at 09:01

4 Answers4

5

I'm using chaining promises like this:

            $http.get('urlToGo')
                .then(function(result1) {
                    console.log(result1.data);
                    return $http.get('urlToGo');
                }).then(function(result2) {
                    console.log(result2.data);
                    return $http.get('urlToGo');
                }).then(function(result3) {
                    console.log(result3.data);
                });
Thiago Pereira
  • 1,724
  • 1
  • 17
  • 31
1

Chaining promises works here : jsfiddle

In your implementation, if $http.get or compactData goes wrong your console.log(data) will not be call.

You should maybe catch errors :

    blubb.getSomething(uri, input).then(function(data) {
       console.log(data);    
    }, function(err) {
       console.log("err: " + err);
    });
Bastien Caudan
  • 4,482
  • 1
  • 17
  • 29
  • i don't know why but there is no output even if i log out the error. but when i use `$rootScope.$apply` it works just fine... BUT i am getting the `Error: $digest already in progress` now – Betty St May 08 '13 at 10:47
1

Whenever you use an external (external to AngularJS) callback that runs in a new turn/tick, you have to call $apply() on the appropriate scope after it has been invoked. This lets AngularJS know it has to update. You'll probably want to make sure you're only calling it once -- after all of the promises have been resolved. As an aside, jsonld.js provides a promises/future API, so if you're already using promises, you don't have to do that wrapper code above. Instead you can do:

var promisesApi = jsonld.promises();
var promise = promisesApi.compact(input, context);

// do something with the promise
dlongley
  • 2,078
  • 14
  • 17
0

I would suggest you to use a Factory instead of a service.

Just return the function from the factory and use it in your controller

Ali Sadiq
  • 900
  • 6
  • 11