Migrate AngularJS to Angular through Angular CLI + Hybrid application

Elena Ortega
9 min readAug 29, 2020

--

The purpose of this tutorial is to provide another way to do the migration from an AngularJS application to the latest version of Angular. At the time that this guideline was done, Angular is at the version 9.

The PhoneCat Upgrade Tutorial will be used as starting point. The oficial Angular documentation about upgrading from AngularJS to Angular uses that project as starting point as well. Find the starting repo here.

The approach that will be taken to migrate that application is different from the one that the official documentation propose. There are different strategies to migrate the application. From the experience of migrating real projects, the approach of taking as starting point a new Angular application builded through the Angular CLI seems to be a good one as it ensures a proper set up, where we will configure a hybrid application so both versions will be working together during the migration time, providing the possibility of new features development at the same time (if needed).

Steps:

  1. Get the AngularJS application
  2. Create a new Angular application using Angular CLI
  3. Copy AngularJS code
  4. Bootstrapping an hybrid application
  5. Set AngularJS as a global variable
  6. Include AngularJS route
  7. Fix errors
  8. Migrate the application’s features
  9. Adjust Routes
  10. Remove AngularJS

1. Get the AngularJS application

Clone the PhoneCat Upgrade Tutorial from the official repository. This code will be the original AngularJS application that will be migrated.

2. Create a new Angular application using Angular CLI

Our starting point will be an empty application that will be generated using the Angular Command Line Interface.

Install globally the CLI using the npm package manager:

npm install -g @angular/cli

Current version of Angular CLI: 9.1.3

Create a new angular project:

ng new angularjs-to-angular

Build and server the application:

cd angularjs-to-angularng serve

Check that the application is up and running (http://localhost:4200/).

Clean the existing app.component.html to remove the example code:

app.component.html

Check the project’s code at this point.

3. Copy AngularJS code

The way that the application will be migrated is going to support the hybrid application, that means that both AngularJS and Angular running at the same time. In order to achieve that we will be moving some code from the original AngularJS application into the Angular application that we have created on the previous step.

3.1 Update Package.json

Copy the dependencies from AngularJS package.json file into the package.json file of the Angular application.

package.json
package.json

After that change, we need to update project, so the new dependencies will be installed:

npm i

3.2 Update third party libraries:

In an AngularJS application, the third party libraries are defined in the index.html file. Whereas Angular declares all the third parties libraries in the file angular.json under the scripts section:

angular.json

In order to apply this changes, we need to stop and run the serve again.

3.3 Update styles:

The scaffold of the Angular application already creates a style.scssfile. Here we can import any external style library:

styles.scss

In order to get the same style of the original project, copy the existing code of app.css into app.component.scss

3.4 Updating the AppModule

Copy the app.module.js from the original AngularJS application into the new Angular application under src/app and rename it to app.module.ajs.js. Renaming it will remind us that this file is needed for the AngularJS (that’s why .ajs. is added)

Modify the file top import the external/internal dependencies:

app.module.ajs.js

Import the app.module.ajs.js into the main.ts file:

main.ts

3.5 Update index.html

Copy the body content of the file index.html of the AngularJS application in the same file of the new Angular application:

index.html

3.6 Add original code

Copy the folder app/core , app/phone-details , app/phone-list into src/app.

Check the project’s code at this point.

4. Bootstrapping an hybrid application

In order to be using both versions of Angular, we need to bootstrap the AngularJS into the new Angular.

Install @angular/upgrade :

npm install @angular/upgrade --save

Import UpgradeModule, remove AppComponent from the bootstrap array and override the ngDoBootstrap method:

app.module.ts

Where phonecatApp is the same name set in theng-app on the index.html file in the AngularJS application. For more information check the official documentation.

Check the project’s code at this point.

5. Set AngularJS as a global variable

The @angular/upgrade/static library exposes a setAngularJSGlobal function. We can use this to load AngularJS into the Angular library.

main.ts

Check the project’s code at this point.

6. Include AngularJS router

Copy the app.config.js from the original AngularJS application into the new Angular application under src/app and rename it to app.config.ajs.js. Renaming it will remind us that this file is needed for the AngularJS (that’s why .ajs. is added)

Having this configuration file will allow to run the hybrid application without the need to rewrite everything at the beginning. As far as we progress on the migration, this file will be partially modified and deleted at the end of the process.

Modify the existing code to export a function:

app.config.ajs.js

Import the app.config.ajs.js into the main.ts file:

main.ts

Check the project’s code at this point.

7. Fix errors

Open the browser console to check and fix the errors:

  • Error: [$injector:nomod] Module ‘ngResource’ is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument. → Include import ‘angular-resource'; in the phone.module.js file
  • angular.js:15635 Error: [$templateRequest:tpload] Failed to load template: phone-list/phone-list.template.html (HTTP status: 404 Not Found) → add src/appunder assets section on angular.json the src/app. Also modify the templateUrl of the phone-list.component.html to point to ./app/phone-list/phone-list.template.html. Stop and run again the server to apply the changes.
  • http://localhost:4200/phones/phones.json 404 (Not Found). Copy the folder app/img and app/phones under src/assets . Modify the json files to point to the proper route in order to get the images (replace any "img/phones…for "assets/img/phones...). Modify the reference inside phone.service.js

The application should be render properly.

Check the project’s code at this point.

8. Migrate the application’s features

8.1 Prepare to use Typescript

Before moving forward to upgrade services and components, we need to start using Typescript. TypeScript is a typed language that compiles to JavaScript. It provides advanced autocompletion, navigation, and refactoring.

To make use of Typescript, we need adjust the configuration:

tsconfig.app.json

Check the project’s code at this point.

8.2 Upgrading Services

Open app.module.ts file, import and add HttpClientModule to the imports array of the AppModule. HttpClientModule replaces ngResource in the new version of Angular.

app.module.ts

Replace the implementation of src/app/core/phone/phone.service.js for an Angular class using typescript (rename to phone.service.ts):

phone-service.ts

Downgrade the service so it could be used by AngularJS components:

phone.service.ts

Load thephone.service.ts through the AppModule:

app.module.ts

Check the project’s code at this point.

8.3 Upgrading Components

Prepare the component code to be migrated, convert the templates into Angular syntax:

phone-list.component.js

Do the following changes in the html file:

  • replace .template.html for .component.html
  • replace $ctrlfor vm
  • replace AngularJS syntax to Angular (e.g. ng-repeat to *ngFor)
phone-list.component.html

Do the same with phone-detail .

Convert both components to typescript and make use of the Phone Service (already migrated to Angular):

phone-list.component.ts
phone-detail.component.ts

Convert AngularJS component definition object into an Angular @Component decorator:

phone-list.component.ts
phone-list.component.html

The new PhoneListComponent uses the Angular ngModel directive, located in the FormsModule. Add the FormsModule to NgModule imports, declare the new PhoneListComponent and finally add it to entryComponents since you downgraded it:

Do the same with phone-detail .

Check the project’s code at this point.

8.4 Transform filters into pipes

The AngularJS directive has a checkmark filter. Turn that into an Angular pipe. There is no upgrade method to convert filters into pipes, it needs to be rewritten.

Now import and declare the newly created pipe:

app.module.ts

The filer and orderBy pipe are not provided, so it is needed to create them.

Check the project’s code at this point.

9. Adjust Routes

Translate the existing code in app.config.ajs.js into the existing file app-routing.module.ts :

app-routing.module.ts

Update the phone-detail component to use the proper route:

phone-detail.component.ts

Check the project’s code at this point.

10. Remove AngularJS

Remove AngularJS injection, the file main.ts may return to the original code:

main.ts

Remove all references to the UpgradeModule from app.module.ts :

app.module.ts

Also remove any downgradeInjectable() or downgradeComponent() you find, together with the associated AngularJS factory or directive declarations. Since you no longer have downgraded components, you no longer list them in entryComponents.

Remove as well as any factory provider for AngularJS services, and the app/ajs-upgraded-providers.ts file.

You may also completely remove the following files. They are AngularJS module configuration files and not needed in Angular:

  • app/app.module.ajs.js
  • app/app.config.ajs.js
  • app/core/core.module.js
  • app/core/phone/phone.module.js
  • app/phone-detail/phone-detail.module.js
  • app/phone-list/phone-list.module.js

The external typings for AngularJS may be uninstalled as well. The only ones you still need are for Jasmine and Angular polyfills. The @angular/upgrade package can also go.

npm uninstall @angular/upgrade angular angular-animate angular-resource angular-route angular-mocks --save

Update bootstraping:

app.module.ts

Add this <app-root> element to the index.html. It replaces the old AngularJS ng-view directive:

index.html

Check the project’s code at this point. At this point we have the application migrated to the new version of Angular :)

--

--