to top

A migration History: from AngularJS 1.3 to 1.5 and then 2.0

I’d like to tell the story of some of our recent experiences with a number of AngularJS version migrations across a range of different projects. It’s a brief overview of what our development team has experienced and the challenges we’ve encountered.

Hopefully, it will help anyone walking the same road. If you’re still developing with earlier versions of AngularJS, this story is for you. By the way, we will be glad to share our experience with your company. Feel free to contact us and get a quote regarding AngularJS development.

Migration History: from Angular 1.3 to 1.5 and then 2.0

We’d been developing with Angular versions 1.2 to 1.3 for quite a while and, I believe, everyone was feeling reasonably comfortable with them. Since its first release back in 2010, AngularJS has matured and grown into a solid and evolved framework loved by thousands of development teams. Two-way data binding, templates, dependency injection, directives – all of these features became so intuitive and flow so smoothly in the earlier versions. This lasted for a number of years, and then, for no apparent reason, the Angular 1.5 release appeared. On the surface, it brought some performance improvements, bug fixes and all the other cute stuff you tend to expect with regular upgrades to new versions. But wait, a new notation was also part of the package – “component.” Was this just another variation on what we were used to seeing prior to 1.5?

Not really. In Angular 1.5, component is a brand new declaration of the client-side logic, designed to maximally decouple it from the external world, allowing it to become more independent and self-sufficient. Could the same achieved in 1.3-1.5? Potentially, yes, if you could thoughtfully write the easily re-usable directive. But it also advocates one-way data binding! Aren’t we going in the wrong direction when we already have a cool two-way data-binding feature?

Let’s examine the simplest button component:

app.component('addButton', {
      bindings: {
            mode: '<',
            onAdd: '&'
      },
      templateUrl: '/pages/app/components/button/addButton.html',
      controller: function() {
            var ctrl = this;

            ctrl.addButtonClicked = function() {
                 ctrl.onAdd();
            }
            ctrl.showButton = function() {
                 return ctrl.mode == 'viewMode';
            }
      }
});

In this example, there’s a mode variable that’s passed from the external manipulating component or page. Apparently, it controls the visibility of the button and it most likely depends on some business conditions outside of the component. Therefore, it should never be explicitly changed inside the button component. If this is the case, isn’t it a good idea to make a mode variable that can bind in one direction via the ‘<’ sign so you can be confident that any manipulations with it inside the component will never affect the external world? No doubt.

But what if the component still needs to communicate with the outer world? Remember, $scope.broadcast() can help, but this is not a panacea. Moreover, rash use of broadcasting can cause some listeners to react even if they’re not supposed to. This happens frequently enough, especially in large enterprise applications with complex pages. An immediate solution for this exists – simply attach an external handler to the method that you’d like to call inside the component. For example, use onAdd, and call it from outside:

<add-button mode="$ctrl.mode" on-add="$ctrl.add()"></add-button>

Apart from this, did the appearance of component somehow affect the well-known AngularJS navigation states? Indeed. This was another interesting and slightly tricky part to migrate. Let’s see, how stateProvider defines the state using template and controller names:

$stateProvider.state(“myState”, {
      templateUrl: “myTemplateUrl”,
      controller: “myController”
});

And this is how stateProvider defines state using just a component name:

$stateProvider.state(“myState”, {
      component: “myComponent”
});

Here the reference to the component HTML template is encapsulated inside the component itself, which makes for cleaner and simpler code. And the trickiest part I’m going to mention here is that such state declarations require an upgrade of angular-route to an appropriate version, one that can work with AngularJS components.

Aside from several features Angular 1.5 brought to development, I believe this version also brought a more fundamental change that affected Angular users – it thinks differently. Although we’d all worked with the earlier versions for years, Angular 1.5 added a specific value that challenged developers to construct their code by looking at it from a different angle. Why? Because explicit one-way data binding and linked callbacks force people to be more diligent about the code they write, create physically re-usable independent components, and thereby decrease the overall LOCs of the projects they build. Having a set of thoroughly developed re-usable components can significantly increase a development team’s performance – and this was definitely part of our recent experience. We were working on a page with around 10 so-called “portlets,” each of which contained a datatable with different columns and sources. Each portlet initially consisted of its own controller and HTML template, and each contained a huge declaration of the datatable. This meant repetitive declarations with a bunch of copy-pasted code. There were approximately 1200 LOCs for the whole page. Each new portlet required a few hours to set up. After re-developing this page using AngularJS 1.5 components, the overall LOCs were cut in half, and the setup time required for each new portlet was less than 15 minutes!

Developing a “component-oriented” perspective also helps developers prepare to dig into Angular 2 style, since components are the building blocks of Angular 2 architecture. Coding Angular 2 will force you to think about your application not in terms of MV*, but as a tree of components. But, I guess, everyone knows there’s no migration path from AngularJS 1 to 2. That’s not a bad thing! If you haven’t already, it’s high time to leave your comfort zone and experience this incredible new product, which has evolved in a different direction than its older brother AngularJS 1. Since its dedicated community had grown considerably in recent years, AngularJS 2 was able to absorb all the brilliant ideas from the all the smartest minds; because of this, there wasn’t much room left for additional upgrades to Angular’s earlier model.

An experience that confirmed the words above took place in one of our most recent developments. Almost all complex enterprise applications involve displaying large amount of data in one way or another, either as graphs or data tables (data grids). A few years ago, an Angular dataTable library was released for AngularJS 1. We successfully implemented this tool in the development of several enterprise applications. When AngularJS 2 appeared, we hoped there would be a successor to this library targeted to new syntax and operations, and we weren’t mistaken! By the time we were ready to try it, the successor has already been released! This feature-rich yet lightweight data-table inherits the coolest features from its older brother, but also adds AoT compilation support, another great feature of Angular 2.