2

this is a follow up to my previous question.

I have an AJAX request which takes some time. Let's say I get two parts of data, var1 and var2. I only want to use var1 in a directive that is bound to main controller scope with

var1: '=',

I get var1 and var2 combined from the service but since they have a different purpose, I cannot simply use the one promise that I get from $http call.

I tried to implement it but it still not working as I supposed. The service is of following form:

myModule.service('MyService', ['$http', '$q', function($http, $q) {
    var var1 = $q.defer();
    var var2 = $q.defer();
    httpPromise = $http({
        url: "/myService",
        method: "GET",
        params: {}
    }).success(function(data, status) {
        var1.resolve(data.var1);
        var2.resolve(data.var2);
    })

    return {
        getVar1: function() {
            return var1.promise;
        },
        getVar2: function() {
            return var2.promise;
        },
    }
}]);

In the controller I assign the promises as follows:

$scope.var1 = MyService.getVar1();
$scope.var2 = MyService.getVar2();

However once the promise is resolved in the service, the directive seems not to know that value for var1 was changed. I thought that this will be handled by AngularJS engine.

It seems to me that the only way here is to make a lot of then() calls that would introduce more mess than good. I think I will stay with (an ugly hack I suppose...)

$scope.$watch('var1', ...)

inside the directive, unless someone shows me a better direction.

Community
  • 1
  • 1
wsk
  • 65
  • 2
  • 7
  • you need to use `then()` to access data resolved by promise. Your `vars` are only promises right now. Also why split them up? Just pass the whole data object to controller and then pass one of the properties to directive. Also no need for `$q` since `$http` returns a promise. Just adding code bloat – charlietfl Jan 23 '15 at 18:33

1 Answers1

3

Seems to me like you would only need to make one then() call, and using then() is the correct way to use promises:

Inside the directive:

var1.then(function (value) {
    // use the resolved value
});

A few side notes on promises:

This is redundant:

return {
    getVar1: function() {
        return var1.promise;
    },
    getVar2: function() {
        return var2.promise;
    },
}

You can just do this:

return {
    var1Promise: var1.promise,
    var2Promise: var2.promise,
};

and then access them like this:

$scope.var1 = MyService.var1Promise;

to get exactly the same result.


You've also fallen prey to the deferred antipattern, which has actually introduced bugs into your code (you will not be able to catch the errors if your $http call fails).

You can implement your service without deferreds, with fewer lines of code, and most importantly with the ability to catch errors, like this:

myModule.service('MyService', ['$http', '$q', function($http, $q) {
    var httpPromise = $http({
        url: "/myService",
        method: "GET",
        params: {}
    });

    return {
        var1Promise: httpPromise.then(function (response) {
            return response.data.var1;
        }),
        var2Promise: httpPromise.then(function (response) {
            return response.data.var2;
        }),
    };
}]);

I'll agree with you that all those .then() calls are not the most beautiful sight in the world. I'll be glad when widespread support for arrow functions gets here.

Community
  • 1
  • 1
JLRishe
  • 99,490
  • 19
  • 131
  • 169