hlovdal
hlovdal

Reputation: 28180

Service to indicate some done criteria using Promise

We have several controllers in an application, for several different tabs/pages. I want to have some mechanism to indicate that something is finished in one of them for use in another controller. Promises should be this mechanism, so I am trying to get a hang of it.

I have played around at http://jsfiddle.net/ExN6Q/ and gotten something that works like I want, but I am not super happy with the result for the services.

If I have the following html:

<div ng-app="myApp">
    <div ng-controller=myController1>
        Fill in this field: <input type="text">
        <input type="submit" value="Done" ng-click="submit()">
    </div>
    <div ng-controller=myController2 ng-show="done1">
        And this field: <input type="text">
        <input type="submit" value="Done" ng-click="submit()">
    </div>
    <div ng-controller=myController3 ng-show="done2">
        As well as this field: <input type="text">
        <input type="submit" value="Done" ng-click="submit()">
    </div>
</div>

and then the following controllers:

my_module.controller('myController1', function ($scope, Done1Service) {
    $scope.submit = Done1Service.done;
});

my_module.controller('myController2', function ($scope, Done1Service, Done2Service) {
    $scope.done1 = false;
    $scope.submit = Done2Service.done;
    Done1Service.get_promise().then(function () {
        $scope.done1 = true;
    });
});

my_module.controller('myController3', function ($scope, Done2Service, Done3Service) {
    $scope.done2 = false;
    $scope.submit = Done3Service.done;
    Done2Service.get_promise().then(function () {
        $scope.done2 = true;
    });
    Done3Service.get_promise().then(function () {
        alert("Congratulations, you're done!");
    });
});

then I am actually satisfied with the result, the "problem" is the implementation of the services:

my_module.factory('Done1Service', function ($q) {
    var deferred = $q.defer();
    var get_promise_fn = function () {
        return deferred.promise;
    };
    var done_fn = function () {
        console.log("I'm done!");
        return deferred.resolve(true);
    };
    return {
        get_promise: get_promise_fn,
        done: done_fn
    };
});

my_module.factory('Done2Service', function ($q) {
    ... // identical except console.log("I'm done again!")
});

my_module.factory('Done3Service', function ($q) {
    ... // identical except console.log("I'm done at last!");
});

These feel a bit too boilerplatish, and I wonder if I am doing something wrong. Could I create one common service and make three instances of it? Is this the normal way to handle this by returning a promise from a dedicated get_promise function ( which I then assume would probably be called something else)?

Upvotes: 0

Views: 42

Answers (1)

plalx
plalx

Reputation: 43718

As it is right now, your services are a one shot deal since promises cannot be reset. I think you could solve this problem by either using a single EventBus service through which every controllers communicates. E.g. The first controller sends a 'step1completed' message on the bus which is intercepted by the second controller, which does it's work and fires a 'step2completed' event, etc.

If you have many identical processes that have to run in parallel, you could allow creating multiple EventBus instances which would serve as independent communication channels for a specific set of objects.

Angular already allow you to emit or broadcast events through scopes, have a look at $emit and $broadcast.

Upvotes: 1

Related Questions