Frameworks and tools like Angular allow developers to create powerful cross-platform web and mobile apps that function as well as—and sometimes better than—native applications.
When it comes to managing these applications and websites, we like to quote Uncle Ben from Spiderman, "...with great power comes great responsibility." The responsibility here is to keep up with updates, changes, and end-of-life notices for the frameworks, tools, and libraries that we use in our clients' projects.
With the end-of-life notice for AngularJS support last December, one of our clients approached us with an exciting challenge. Civilian and government customers use their product—and the end of support for AngularJS meant critical security patches wouldn't be available for their product.
Thankfully the Angular team had a plan for helping developers migrate from AngularJS to Angular—a library called ngUpgrade, which allows AngularJS and Angular code to run together in the same application. The ngUpgrade library provided by Angular is powerful—you're able to upgrade AngularJS components. Hence, they are visible to Angular projects, and you're also able to downgrade an Angular component, so it is visible to an AngularJS project.
Running AngularJS components inside the project wouldn't remove the security issues. Still, it would provide the necessary time to update the project component by component without rewriting the entire web application from the ground up.
We presented a plan to our client to create a proof of concept (POC) to see if the ngUpgrade solution would work for their application.
Getting started with the proof of concept
The app in question is a cloud-based web app built in 2014 that uses Rails and AngularJS as the foundational frameworks. The project also uses familiar web tools, including Sprockets, Slim for their HTML templates, and Sass for the CSS.
In addition to moving from AngularJS to Angular, we also worked with the client to upgrade the version of Ruby on Rails being used to move to webpack instead of Sprockets for asset management.
Next, we moved the AngularJS code into a separate folder and added a simple HTML page to confirm that the connection to the project database still worked. After removing AngularJS, we added Angular with webpack into the project.
It was smooth sailing until we started to look at the tutorials and examples provided by Angular. Most of the tutorials and examples for migrating from AngularJS to Angular were produced in 2018. While we could follow some of the tutorials, we found multiple gaps and inconsistencies. Another challenge was that this was a Rails and AngularJS project.
Upgrading an AngularJS app to Angular would be much more straightforward. But in this project, Rails made it a more complicated process—especially for the number of frameworks involved in the pipeline and asset management. Time was of the essence, so we decided to create a proof of concept of one of the project's components to show how the larger migration project would work.
What we learning from the project
Here are four things we learned from creating the proof of concept project
Angular requires strictly valid HTML
One of the major differences between Angular and AngularJS is that Angular has a strict requirement for valid HTML. Shortcuts such as <div class=" sample"/> will cause errors in an Angular project. The cause here is that AngularJS served the HTML directly to the browser. Angular tries to process the HTML before serving it to the browser.
Missing class names
Another issue is due to mixing webpack and AngularJS. AngularJS does dependency injection using class names—and bases it on the name of the class. But when we use webpack, the code is minified, and we lose the class names. The minification process causes the dependency injection to fail because the code asks for a component and cannot find it. We used the ng-annotate package as a workaround. The issue is that it needs to be run manually to annotate the class names, as letting it run automatically on all the code can produce errors during runtime.
Convert twice, run once?
Even though AngularJSS can be used as a component in Angular, it needs to be modern AngularJS as older AngularJS will throw more errors. The main problem we presented back to the client was this—the AngularJS code would first need to be updated to the latest version of AngularJS, and then it would need to be converted to an Angular component using ngUpgrade.
Components vs. Directives
Since it used an older version of AngularJS, our client's application primarily used directives. While components and services work well in this hybrid model, directives have a few strict requirements:
Directives can work in Angular if they…
- Must be an element directive, not attribute directive
- Needs a controller and template
- Needs isolated scope
- Needs to use bindToController (new in 1.6)
- No compile or link functions
The final decision
The ultimate question for our client was what benefit does pursuing a hybrid app get them. The main benefit of a hybrid app is sharing components and services between AngularJS and Angular. If you have a very componentized page and those components are shared across your whole application, you can start converting these individual components and start using them in pages.
Because their project is from 2014 and contained mainly directives, the client asked us to create a second proof of concept using a side-by-side model with one fully Angular app and one fully AngularJS app. The idea was that they could then rewrite one whole page of the app since there wasn't much need for such sharing of services and components.
As a team, this was an important reminder that proof of concepts aren't meant to validate every idea. This wasn't a failure—it was a success because we helped the client avoid going down a path that would have required significant rework on code that would be rewritten for the new Angular project.