6

I have a Service which wraps my API calls in Angular:

var ConcernService = {

    list: function (items_url) {
        var defer = $q.defer();
        $http({method: 'GET', 
            url: api_url + items_url})
            .success(function (data, status, headers, config) {
                defer.resolve(data, status);
            })
            .error(function (data, status, headers, config) {
                defer.reject(data, status);
            });
        return defer.promise;
    },

Then my app config, with UI-Router:

    .config(function($stateProvider){

        $stateProvider

        .state('default', {
            url: '/',
            resolve: {
                tasks: function ($stateParams, ConcernService) {
                    return ConcernService.list('tasks/').then(
                        function (tasks)   { return tasks; },
                        function (reason)  { return []; }
                    );
                },
                ...
            }
        }
    });

This is the most basic configuration I could get away with, which basically just returns an empty object if a 403, 404 etc is encountered and I can handle that in the view, template.

My question is, what is the best approach for getting the other detail to the view/ template, such as the rejection reason and status. Should it be returned in the tasks object, or separately?

halfer
  • 19,824
  • 17
  • 99
  • 186
Darwin Tech
  • 18,449
  • 38
  • 112
  • 187

1 Answers1

7

Well, first of all, your first bit of code has the deferred anti pattern, let's fix that:

list: function (items_url) {
    return $http.get(api_url + items_url); // $http already returns a promise
},

Also note, that deferred rejections and fulfillments are single value, so your multiple return values don't really work here.

Now, let's look at the router. First of all, your first fulfillment handler is redundant.

.state('default', {
        url: '/',
        resolve: {
            tasks: function ($stateParams, ConcernService) {
                return ConcernService.list('tasks/'); // result.data contains the data here
            },
            ...
        }

Now, the problem we have here is what happens in case of a rejection?

Well, listen to $stateChangeError:

$rootScope.$on('$stateChangeError', 
function(event, toState, toParams, fromState, fromParams, error){ ... })

Here, you can listen to change state failures from rejections.

Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • Hey Benjamin - thanks for the pointers on my code. I did think it was a little long-winded. I do understand promises a little better now. As for the state change error expression - should this go in my `app.config`? And then do a just map the various errors to the states I want? – Darwin Tech May 28 '14 at 17:46
  • Right. Implementation works. for the record I added the `stateChangeError` statement to the `app.run()`, and I can pass along the error object to a generic partial template to display context-specific messages. Thanks! – Darwin Tech May 29 '14 at 16:59