4

One of my promises during feeds.forEach cycle ends up with error. Maybe because this in LoadData never executes line $rootScope.links = urls; which is inside then. How to fix it?

app.service('LoadData', ['FeedService', 'EntryStateUrlService', '$q',
 function(FeedService, EntryStateUrlService, $q) {
   this.loadData = function(feedSrc) {

     FeedService.parseFeed(feedSrc).then(EntryStateUrlService.getEntryStateUrl).then(function(data) {
       console.log(data);
       $rootScope.links = data;
     });
   }
 }
]);

app.service('FeedService', function($http, $q) {
 this.parseFeed = function(url) {
   var deferred = $q.defer();
   $http.jsonp('//ajax.googleapis.com/ajax/services/feed/load?v=1.0&callback=JSON_CALLBACK&q=' + encodeURIComponent(url))
     .success(function(res) {

       deferred.resolve(res.data.responseData.feed.entries);
     }).error(function() {
       deferred.reject();
     });
   return deferred.promise;
 }
});

app.service('EntryStateUrlService', ['$state', '$q',
 function($state, $q) {

   this.getEntryStateUrl = function(feeds) {

     var deferred = $q.defer();
     var idx = 0,
       promises = [],
       promise = null;
     feeds.forEach(function(e) {
       promise = $http.jsonp(e.link).success(function(data) {
         /*stuff*/
        e['entryStateUrl'] = data.link; // UPDATED
         deferred.resolve(data);
       });
       promises.push(promise);

     }); //forEach
     return $q.all(promises);
   }
 }
]);

UPDATE I don't really understand how $q.all as a big promise object composite of many other promises will deliver data to service LoadData....

UPDATE2

It seems like since one promise fails (because the one of the urls is invalid) $q.all fails and never makes to then(). How to go around that? I need to get all data from all successful promises.

Community
  • 1
  • 1
Mbps
  • 43
  • 3
  • What error message do you get? – mindparse Feb 04 '15 at 16:31
  • One call `$http.jsonp` in `EntryStateUrlService` fails. Chrome console prints out red `GET` record. Others succeed. When setting break-point on `$rootScope.links = urls;` it never stops. – Mbps Feb 04 '15 at 16:34

1 Answers1

3

One thing is you'll need to inject $rootScope in order to use it:

app.service('LoadData', ['FeedService', 'EntryStateUrlService', '$q', '$rootScope',
 function(FeedService, EntryStateUrlService, $q, $rootScope) {
    //...
 }
]);

Also in the Q library there's a method called allSettled that will allow you to view all the promise results even if one fails. The angular $q does not have this method, but several people have found it useful so they've created extensions for it. Here's an example of one on a Github Gist:

angular.module('qAllSettled', []).config(function($provide) {
  $provide.decorator('$q', function($delegate) {
    var $q = $delegate;
    $q.allSettled = function(promises) {
      return $q.all(promises.map(function(promise) {
        return promise.then(function(value) {
          return { state: 'fulfilled', value: value };
        }, function(reason) {
          return { state: 'rejected', reason: reason };
        });
      }));
    };
    return $q;
  });
});

Using this method will return all results, whether rejected or not. The returned object will have a state property that will tell you the status of the promise:

return $q.allSettled(promises);

Then you can check the status of each promise and add it to the links as needed:

FeedService.parseFeed(feedSrc)
    .then(EntryStateUrlService.getEntryStateUrl)
    .then(function(results) {
        $scope.links = [];
        results.forEach(function (result) {
            if (result.state === "fulfilled") {
                $scope.links.push(result.value);
            } else {
                var reason = result.reason;
            }
        });
});

Plunker Demonstration

Dan-Nolan
  • 6,594
  • 4
  • 27
  • 32
  • There is a problem with this solution: http://stackoverflow.com/questions/28342963/strange-behavior-promise-returned-twice – J.Olufsen Feb 05 '15 at 16:16