Recently angularjs has caught huge attention from frontend developers. There are many frameworks available to choose from and most of them are baked with very common features. EmberJS that started way before AngularJS and backed by Apple, ExtJS which is also a full featured MVC framework, and then the Backbone.js. What is driving most of us to AngularJS is the community that is very active for resolving issues and has huge interest from tech world to extend its capability. And now with its recent development in TypeScript, it’s teasing lot more developers to play with it.
There have been many changes in this library that diverted lot of us to think this library is not going in right direction and may disappear just like other frameworks. But as of now Angular is still evolving and keeping our interest in it.
From my past experience working with AngularJS and having .net background I found there is something that really missing or not standardized when compared with other MVC frameworks. It’s not that AngularJS does not provide those feature at all but problem is no one is focusing on those aspects as a framework rather just tries to use it as is because some top blogger says so. Well one size cannot fit all. Maybe the way I want to setup this framework, others would not even require.
This article is not to discuss on what this framework is or what the alternatives to angularjs are. Rather we are going to look deeper into some aspects of framework to overcome the boilerplate code to make use of AngularJS even sweeter.
@inject, @injectable, $inject, $injector… what?
Dependency injection has been the most interesting feature of AngularJS. It is the most valuable aspect of development for complicated applications with lots of interrelated modules and services.
Please read the Angular implementation from official site https://docs.angularjs.org/guide/di.
So this thing works great, what exactly the problem is here?
- You have to pass all the dependencies in parameters. Unquestionably not a best practice and not maintainable. Imagine you need more than 5 dependencies to inject everywhere. And let’s say you were almost at the half way through development and some design change needs some more dependencies.
- Other problem described in official guide is dependency parameter name changes in minifiaction process that makes Angular unable to find the correct dependencies. Angular provides workaround by allowing to provide $inject variable or inline parameters to specify those dependencies as array in string format (v1.5 and earlier), @injectable and @inject (v2+). That’s good. But that also adds more cons to my first point I mentioned above since now you have to take care of additional strings, its casing in conjunction to adding parameter in constructor and most importantly its order.
- Angular doesn’t really know whether dependencies you need are loaded or not. And doesn’t provide any way to load it from server if it’s not loaded. That means you either always have to load all the dependencies before your constructer invokes, including interrelated dependencies. Which quite not practical in real world complex application development.
Let’s try to see how we can get over these issues.
One quick solution that I think of is Service Locator pattern. In fact Angular provides the service locator using $injector. Great that solves our second problem. If we just inject that object as parameter and our code will look nice.
But if developers add this code everywhere they requires, then it will be even worse than the actual problem we are trying to fix. I’ll rather have common service or factory that provides dependency instances whenever I need.
Great we worked around our first 2 issues and now developers have to inject only service locator, that’s a big improvement.
We can still improve this further by using inheritance. So basically we will abstract these common injection part to parent classes and developers will just have to implement those parent and done. That’s a huge improvement when we compare our original implementation with this approach.
Similarly, we will implement the BaseController to use this ServiceLocator
There are two additional things to notice:
First, I have made BaseController generic to implement IScope type. It’s just to define scope object for every controller inheriting from this base class.
And second is Init abstract method. Since we have to predefine the constructor we don’t want developer to define that again in child controllers but we still need to have a method that get invoked while creating the instance.
Right I’m not worrying about controllerAs part since my implementation is just for illustration purpose.
Finally, our controller will look like this.
That’s it, isn’t it clean and maintainable? Developer will focus less on taking care of Angular and more on the functionality.
We can implement the Components in similar fashion. It needs some extra things to take care to work with AngularJS. That I’ll cover in next article.
Another issue that I mentioned at the beginning is dynamically loading the services, we didn’t really solve that yet. I’ll be showing that as well in my next article with complete source code.
Hope it gives some idea and motivates developers to use AngularJS as a framework than just a library.