Last Updated: February 25, 2016
·
2.331K
· tomjakubowski

decorate Angular's $log service to debug long Promise chains

I often find myself needing to log values from the middle of a long promise chain to debug intermediate transformations. But writing:

somePromise
  .then(transformValue)
  .then(function (val) {
    $log.log(val);
    return val;
  })
  .then(function (val) {
    // do something with the transformed value
  });

is a drag. Fortunately Angular exposes a great decorator feature which allows you to modify existing services to suit your needs:

app.config(function ($provide) {
  /**
   * Decorates the $log service to make it a callable function
   * which returns the value of its first argument. Useful for
   * 'tapping' into Promise chains.
   */
  $provide.decorator('$log', function ($delegate) {
    var better$log = function (x) {
      $delegate.log.apply($delegate, arguments);
      return x;
    };

    // copy the original $log properties back onto the enhanced $log
    angular.extend(better$log, $delegate);
    return better$log;
  });
});

This makes it easy to log the intermediate values of a long Promise chain, while maintaining the existing $log service API:

app.controller('AppCtrl', function ($scope, $http, $log) {
  $scope.getGists = function () {
    $log.log('Logging like normal?', true);
    $http.get('https://api.github.com/')
      .then($log)
      .then(function (res) {
        return $http.get(res.data.public_gists_url);
      })
      .then($log)
      .then(function (res) {
        $scope.gists = res.data;
      });
  };
});

As a nice side-effect, you get a shorter and more convenient way to use $log from anywhere (just call it!). A working Plunker is available here.

Have a fresh tip? Share with Coderwall community!

Post
Post a tip
Did you know?

JavaScript on a page runs with the privileges of that origin. One altered library, tag manager, or snippet can read inputs, change what people see, and call your APIs as the user.

Security insights from Cside