Dor Moshe

@dormoshe

Angular v4: Hybrid Upgrade Application

March 28th 2017

This article originally appeared on dormoshe.io

Angular version 4 is out and now we can enjoy its benefits. As explained in the Top 8 Resources to Explore Angular 4, the advantages of the version are enormous. It contains performance improvements, better error messages, smaller modules, brand new features and a lot of improvements to the v1-v4 hybrid application. Version 4 brings with her changes in the upgrade and downgrade processes, in order to support AOT compilation for the hybrid application.

In this article, we will cover the new way to upgrade an application from AngularJS to Angular v4. In order to work comfortably with the new way, we will build a wrapper that simplifies our coding.

One of the keys to a successful upgrade is to do it incrementally, by running the two frameworks side by side in the same application and porting AngularJS components to Angular one by one. This makes it possible to upgrade even large and complex applications without disrupting other business because the work can be done collaboratively and spread over a period of time. The upgrade module in Angular has been designed to make incremental upgrading seamless.

The old way — Upgrade Adapter

Until version 2.2.0, in order to build a hybrid app, we used the Upgrade Adapter. The upgrade adapter needed to be instantiated with the main app @NgModule. All the upgrade and downgrade processes were done via the adapter. Sometimes it was too complicated and cause to circular dependency that solved by the forwardRef function.

Upgrade adapter instantiation — the old way

And the bootstrapping looks like:

Bootstrapping the application using the upgrade adapter

The new way — UpgradeModule and static function

Version 2.2.0 brings us module that used to bootstrap the application and allows AngularJS and Angular v4 components to be used together inside a hybrid upgrade application, which supports AOT compilation. This module called UpgradeModule and needs to be imported via the @NgModule.imports array.

Therefore, we need to install the @angular/upgrade package via npm and add a mapping for the @angular/upgrade/static package in our system.config file:

A configuration of system.js for the static folder of the upgrade npm

The upgrade module is a very useful tool for upgrading anything but the smallest of applications. With it, we can mix and match AngularJS and Angular components in the same application and have them inter-operate seamlessly. That means we don’t have to do the upgrade work all at once since there’s a natural coexistence between the two frameworks during the transition period.

App module file — import the UpgradeModule and use ngDoBootstrap lifecycle hook

We need to add an override to prevent Angular from bootstrapping itself in the form of the ngDoBootstrap empty class method.

And the bootstrapping looks like:

Bootstrapping the application using the UpgradeModule

HybridHelper

In order to do the upgrade and downgrade of the building blocks (services, providers, factories, directives, components) angular brings us static functions and a base class to extend. The static functions and the base class are parts of the @angular/upgrade/static.

Building blocks tree — mix, mix and mix

Because of the changes in the hybrid process, I decided to build helper called HybridHelper. The helper is a wrapper for the Angular upgrade and downgrade API. It helps us to separate our application from the changes of angular hybrid process. Also, it brings us readability and used as a black box for our purposes.

HybridHelper interface

Downgrade a Component

When you have a v4 component and you want to use it in a v1 template (via another component, directive or route) you suppose to downgrade the component.

Here is our document component. You can see that there are 4 inputs and 3 outputs.

v4 component with inputs and outputs

And the registration of the component in the NgModule:

v4 module with entryComponent metadata

Since this component is being used from the v1 module and is an entry point into our Angular application, we also need to add it to the entryComponents for our Angular module.

The downgrading operation uses the downgradeComponent function.

downgradeComponent(moduleName: string, componentSelector: string, componentClass: any, options?: IComponentUpgradeOptions): IHybridHelper

  • moduleName —v1 module name
  • componentSelector—v1 component selector
  • componentClass — component class type
  • options — optional field for inputs and outputs.
  • options.inputs — An array of strings that specify what inputs the component accepts
  • options.outputs— An array of strings that specify what outputs the component accepts
component downgrading using the helper

You can see that we must provide information about the component being downgraded. This is because once the AOT compiler has run, all metadata about the component has been removed from the code, and so cannot be inferred.

Downgrade an Injectable

When you have a v4 injectable (like a service) and you want to use it in v1 by the dependency injection mechanism (via another component, service or provider) you suppose to downgrade the service.

Here is our documents service. There are no changes in the service or in the NgModule.

v4 service

And the registration of the component in the NgModule:

v4 module for registering a service

The downgrading operation uses the downgradeProvider function.

downgradeProvider(moduleName: string, providerName: string, providerClass: any): IHybridHelper

  • moduleName — v1 module name
  • providerName—v1 provider name
  • providerClass— provider class type
downgrading v4 service

So simple… :)

Upgrade a Provider

When you have a v1 service/factory/provider and you want to use it in v4 by the dependency injection mechanism (in another provider or component) you suppose to upgrade the service.

Here is our document converter service:

v1 service for upgrading

Unlike the downgrading process, upgrading a provider require the building of provider object with a factory method. The HybridHelper wrap this to simplify these steps.

So the upgrade operation uses the buildProviderForUpgrade function in the NgModule file.

buildProviderForUpgrade(ng1Name: string, ng2Name?: string): FactoryProvider

  • ng1Name— v1 provider name
  • ng2Name—optional parameter for v4 provider name (default: ng1Name value)
v4 module with registration of upgraded v1 service

Upgrade a Component

When you have a ng1 component and you want to use it in a ng4 template (via another component, directive or route) you suppose to upgrade the component.

Here is our document stars v1 directive:

v1 directive for upgrading

We can upgrade this component to v4 using the UpgradeComponent class. By creating a new v4 directive that extends UpgradeComponent and doing a super call inside its constructor, we have a fully-upgraded v1 component to be used inside Angular.

We can upgrade this component to v4, annotate inputs and outputs in the upgrade directive, and then provide the input and output using v4 template syntax.

upgrading v1 directive via v4 directive by class inheritance

Upgraded components are v4 directives, instead of components, because Angular is unaware that AngularJS will create elements under it. As far as Angular knows, the upgraded component is just a directive — a tag — and v4 doesn’t have to concern itself with its children.

All that is left is to add it to AppModule's declarations array:

v4 module with registering of upgraded v1 directive

HybridHelper — The code

Here is the code of the wrapper that does the magic

HybridHelper full code

As you can see, the downgrade functions return the HybridHelper instance to support chaining. Here is an example for hybrid downgrading file that demonstrates the use of the chaining feature:

File contains some downgrading components and services with chaining

Conclusion

Version 4 contains a lot of improvements and viable changes for the hybrid applications. This version supports the static way and also is backward compatible white the upgrade adapter. The documentation of the old way has been removed from angular.io, so you can guess what they prefer for us.

The source code of the examples can be found in my GitHub repository.

You can follow me on dormoshe.io or Twitter to read more about Angular, JavaScript and web development.

More by Dor Moshe

More Related Stories