Part 1 - Extending AngularJS with the help of TypeScript
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 the 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 is really missing or not standardized when compared with other MVC frameworks. It’s not that AngularJS does not provide those features at all but the 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 it.
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 the official site at https://docs.angularjs.org/guide/di.
Reference: https://docs.angularjs.org/guide/di
So this thing works great, what exactly is the problem 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 the official guide is dependency parameter name changes in minification 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 string
s, 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 constructor invokes, including interrelated dependencies. Which is not quite 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.
Reference: https://docs.angularjs.org/api/auto/service/$injector
But if developers add this code everywhere they require, 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 parts to parent classes and developers will just have to implement those parents and done. That’s a huge improvement when we compare our original implementation with this approach.
I can use same BaseService
class to implement my other services as illustrated in above code.
I can also call the HTTP() method to get data asynchronously from server, just return promise object from GetItems method above and handle it from caller.
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 the developer to define that again in child controllers but we still need to have a method that gets invoked while creating the instance.
Right, I’m not worrying about controllerAs
part since my implementation is just for illustration purposes.
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 a similar fashion. It needs some extra things to take care to work with AngularJS. I’ll cover that in the 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 the complete source code.
Hope it gives some idea and motivates developers to use AngularJS as a framework than just a library.
Part 2 >>