34

i have been able to get controller to use the $on listener with $scope.$on.

but i don't see any documentation on how to get services to listen for events.

I tried $rootScope.$on, but that only allows one listener. i want listeners in multiple services regardless of whether their parent controllers are in scope or not.

Anton
  • 7,709
  • 5
  • 31
  • 33
  • Why dont you simply inject service into controller and let controller call the service method. You do not need to use any event. (BTW, service wont get created if you dont inject into something...) – Tosh May 10 '13 at 08:55
  • i have multiple controllers and they each have services, all the services need to be notified. not just the controller that is active – Anton May 10 '13 at 11:41
  • @Anton : Services are singletons by default - so changing a services variable in one controller will change it everywhere ( since its the same object ). – ganaraj May 10 '13 at 15:02
  • @ganaraj my services are used to store controller data i want to retain. i have many services and i dont want each controller to have to know about all of them. (yes knew about the singleton aspect) – Anton May 10 '13 at 22:58

2 Answers2

47

after experimenting a fair bit it turns out that getting events to the service can be done with minimal code.

sample service code follows in case anyone else runs into this.

The sample saves and restores the service model to local storage when it gets the respective broadcasts

app.factory('userService', ['$rootScope', function ($rootScope) {

    var service = {

        model: {
            name: '',
            email: ''
        },

        SaveState: function () {
            sessionStorage.userService = angular.toJson(service.model);
        },

        RestoreState: function () {
            service.model = angular.fromJson(sessionStorage.userService);
        }
    }

    $rootScope.$on("savestate", service.SaveState);
    $rootScope.$on("restorestate", service.RestoreState);

    return service;
}]);
Anton
  • 7,709
  • 5
  • 31
  • 33
  • 1
    Am I the only one who notices this is technically a factory object....it doesn't call a service constructor with `app.service('myActualService', ...)` – BradGreens May 12 '14 at 21:42
  • @BradGreens, i find it perplexing myself that app.factory is listed as "a way" to define services in angular. happy to be shown the right way to do it if this is incorrect – Anton May 12 '14 at 23:00
  • Yep, I'm with you. I mostly user `app.service` for true singletons that use `this` properties. I can take a shot at directly porting this `factory` to a `service` tomorrow in hopes it helps outline the difference. Honestly though, I could interchange every service with a factory in my application and not see a difference in the end result. – BradGreens May 13 '14 at 03:05
  • 1
    Also, there's a good at the following link, but it does not change my opinion on the matter of service vs. factory. I could write my complete app in either pattern and it would have zero ability to improve or differentiate the functionality. http://stackoverflow.com/questions/15666048/angular-js-service-vs-provider-vs-factory – BradGreens May 13 '14 at 03:08
  • 1
    I got around to providing an example if this factory were implemented as a service - http://pastebin.com/9q0HMtJy. This doesn't mean it's the "right" way, it's just a way to do the exact same thing in a different Angular way... – BradGreens May 16 '14 at 16:02
13

Since $on is a scope method, you could create a scope in your service, then listen for events on it:

app.factory('myService', function($rootScope) {
    var scope = $rootScope.$new();  // or $new(true) if you want an isolate scope
    scope.$on('testEvent', function() {
        console.log('event received');
    })
    return {}
});

function MyCtrl($scope, myService, $rootScope) {
    $rootScope.$broadcast('testEvent');
}

fiddle

However, I would not recommend this approach, since scopes are not normally associated with services.

svassr
  • 5,538
  • 5
  • 44
  • 63
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • 2
    agreed, using a scope in a service seems curious – Anton May 10 '13 at 23:06
  • 1
    If you don't recommend this approach, what would you do instead? – marcel Mar 12 '14 at 08:27
  • @marcel, I like Anton's approach/answer. (When I first wrote this answer, I couldn't think of a better way.) – Mark Rajcok Mar 12 '14 at 15:54
  • this to me seems also like the correct answer, but a little dubious since scopes are related to controllers – psp Oct 13 '14 at 07:04
  • There are some interesting design patterns using event driven cycles that could benefit from this approach. It might seem curious, but it definitely works very well for me to centralize event dispatchers and attach subscribers. – Ray Suelzer Jul 18 '15 at 15:52