AngularJS – extending existing services using decorator

One of the features I miss the most in AngularJS is ability to easy unsubscribe event handlers. There is no convenience function opposed to $on, so in order to unsubscribe event, we have to call method returned by $on function

However in my opinion this approach fails in real life scenarios, because usually we are subscribed to more than one event – thus we have to have multiple local variables for detaching listeners. Fortunately AngularJS provides an easy way to extend existing services with some new functionalities – we can achieve that by using $provide service. This service exposes decorator method, which is able to intercept creation of any service, so we are able to augment it with some new functions. The best moment to call $provide.decorator method is during module configuration, thanks to this approach we are sure that our custom logic is invoked before module is started.

In my case I wanted to extend $rootScope with new method $un for unsubscribing events, so I called method decorator with parameter ‘$rootScope’ (note single quotation marks) – this tells Angular that I will be modifying $rootScope service

Because I passed ‘$rootScope’ as a first argument of $provide.decorator method, the $delegate parameter in extendRootScope function is actually a $rootScope service. Now having access to the service I can augment it with my custom logic for detaching event handlers.

Entire code listing looks then as follows

From now on, you can unsubscribe events handlers simply by calling $un method

and our listener will react only once

AngularJS
Source code for this post can be found here

AngularJS – extending existing services using decorator

AngularJS – dependency injection

There are couple of ways of injecting dependencies into AngularJS components. The most common one is just to specify the dependency name in the function’s argument list

However this technique fails in real life scenarios, because for production we usually (or rather always) minify and uglify javascript files. Uglify proces renames our variables and due to the fact that dependencies are resolved by name, AngularJS is not able to find appropriate services, directives etc. To overcome this limitation, we can enclose our function definition into an array, and specify dependencies as a string literals. Our original code becomes then

Although this works fine even after minifying and uglifiyng js files, for me this code is hard to read. That is why I like to use yet another technique. This technique leverages variable hoisting and $inject property

As You can see I extracted controller function into separate variable “shellController” and listed all necessary dependencies in $inject array

It is even possible to enhance a bit this example and make it a little less error prone. With the current implementation we have to make sure that order of properties in $inject array is the same as in function declaration. It is easy to keep track of that if we have just a couple of dependencies, but it might be a bit of a pain if we start to add, remove or edit them. Fortunately we can automate this task and basically autogenerate $inject array. In order to do that I like to use Gulp (although it is also possible to use Grunt). First of all we have to install Gulp. There is great tutorial how to do that in here https://github.com/gulpjs/gulp/blob/master/docs/getting-started.md Having Gulp on board we have to install additional packages: gulp-rename and gulp-ng-annotate. In order to do that type into command line

Now we can create gulp.js file which should look more or less like that

We can run this task typing into command line

gulp dependency injection
And as a result our original code (notice lack of dependeny annotations – no $inject arrray)

Will be transformed into

AngularJS – dependency injection