Heather Roberts Heather Roberts - 4 days ago 5
AngularJS Question

Decorate Angular's $log to use a service that uses $http

I am trying to extend the

$log
service so that it also sends a message to a server. I am getting an error from Angular "Circular dependency found" as
$http
uses
$log
.

app.js:

angular.module("app").config(function($provide) {
$provide.decorator("$log", function($delegate, NodeLogger) {
var logFn = $delegate.log;
$delegate.log = function(message) {
NodeLogger.log(message);
logFn.apply(null, arguments);
};
});
});


NodeLogger.js:

angular.module("app").factory("NodeLogger", function($http) {

function log(type, message) {
var logMessage = type + ":" + message;
$http.post("http://localhost:3000/log", "message=" + logMessage);
}

return {
log: log
}
});


I have tried using
$injector
in
app.js
to load
$http
and just make the
POST
request, but it gives the same error. Is there a way to get around this? Can I avoid using
$http
/
$resource
?

Thanks!

PSL PSL
Answer

This is a common issue of circular dependency when $http already injects $log and by decorating it with injecting your factory NodeLogger which inturn injects $http you are creating circular dependency. Instead of injecting your factory directly get the factory from injector, another way is to inject the $injector in your factory and get the $http instance from injector instead of injecting $http directly. This way you avoid circular dependency during factory creation. One important note is to return $delegate without which $log service will not hold any instance.

$provide.decorator("$log", function($delegate, $injector) {
    var logFn = $delegate.log;
    $delegate.log = function(message) {

      //Get NodeLogger factory instance from injector
      var NodeLogger = $injector.get('NodeLogger');
      NodeLogger.log(message);
      logFn.apply(null, arguments);
    };
    //Return the delegate
    return $delegate;
  });

angular.module("app", []).factory("NodeLogger", function($http) {

  function log(type, message) {
    var logMessage = type + ":" + message;
    $http.post("http://localhost:3000/log", "message=" + logMessage);
  }

  return {
    log: log
  }
}).config(function($provide) {
  $provide.decorator("$log", function($delegate, $injector) {
    var logFn = $delegate.log;
    $delegate.log = function(message) {
      var NodeLogger = $injector.get('NodeLogger');
      NodeLogger.log(message);
      logFn.apply(null, arguments);
    };
    return $delegate;
  });
}).run(function($log) {
  $log.log("Hey");
});;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>

<div ng-app="app"></div>

Comments