angular JS - communicate between non-dependend services

I am new in angular and encounter a catch-22:

Facts:

  1. I have a service that logs my stuff (my-logger).

  2. I have replaced the $ExceptionHandler (of angular), with my own implementation which forwards uncaught exceptions to my-logger service

  3. I have another service, pusher-service, that needs to be notified whenever a fatal message is to be logged somewhere in my application using 'my-logger'.

Problem:

I can't have 'my-logger' be depend on 'pusher' since it will create circular dependency (as 'pusher' uses $http. The circle: $ExceptionHandler -> my-logger -> pusher -> $http -> $ExceptionHandler...)

My attempts:

In order to make these 2 services communicate with each other, I wanted to use $watch on the pusher-service: watches a property on $rootscope that will be updated in my-logger. But, when trying to consume $rootScope in 'my-logger', in order to update the property on which the 'pusher' "watches", I fail on circular dependency as it turns out that $rootscope depends on $ExceptionHandler (the circle: $ExceptionHandler -> my-logger -> $rootScope -> $ExceptionHandler).

Tried to find an option to get, at runtime, the scope object that in its context 'my-logger' service works. can't find such an option.

Can't use broadcast as well, as it requires my-logger to get access to the scope ($rootScope) and that is impossible as seen above.

My Question:

Is there an angular way to have two services communicate through a 3rd party entity ?

Any idea how this can be solved ?

Use a 3rd service that acts as a notification/pubsub service:

.factory('NotificationService', [function() {
    var event1ServiceHandlers = [];
    return {
        // publish
        event1Happened: function(some_data) {
            angular.forEach(event1ServiceHandlers, function(handler) {
                handler(some_data);
            });
        },
        // subscribe
        onEvent1: function(handler) {
            event1ServiceHandlers.push(handler);
        }
    };
}])

Above, I only show one event/message type. Each additional event/message would need its own array, publish method, and subscribe method.

.factory('Service1', ['NotificationService',
function(NotificationService) {
    // event1 handler
    var event1Happened = function(some_data) {
        console.log('S1', some_data);
        // do something here
    }
    // subscribe to event1
    NotificationService.onEvent1(event1Happened);
    return {
    someMethod: function() {
        ...
        // publish event1
        NotificationService.event1Happened(my_data);
    },
    };
}])

Service2 would be coded similarly to Service1.

Notice how $rootScope, $broadcast, and scopes are not used with this approach, because they are not needed with inter-service communication.

With the above implementation, services (once created) stay subscribed for the life of the app. You could add methods to handle unsubscribing.

In my current project, I use the same NotificationService to also handle pubsub for controller scopes. (See Updating "time ago" values in Angularjs and Momentjs if interested).

Yes, use events and listeners.

In your 'my-logger' you can broadcast an event when new log is captured:

$rootScope.$broadcast('new_log', log); // where log is an object containing information about the error.

and than listen for that event in your 'pusher':

$rootScope.$on('new_log', function(event, log) {... //

This way you don't need to have any dependencies.

I have partially succeeded to solve the case: I have created the dependency between 'my-logger' and 'pusher' using the $injector. I used $injector in 'my-logger' and injected at "runtime" (means right when it is about to be used and not at the declaration of the service) the pusher service upon fatal message arrival. This worked well only when I have also injected at "runtime" the $http to the 'pusher' right before the sending is to happen.

My question is why it works with injector in "runtime" and not with the dependencies declared at the head of the service ?

I have only one guess: its a matter of timing: When service is injected at "runtime", if its already exists (means was already initialized else where) then there is no need to fetch and get all its dependencies and thus the circle is never discovered and never halts the execution.

Am I correct ?