Migrate AngularJS to Angular through Angular CLI + Hybrid application
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:
- Get the AngularJS application
- Create a new Angular application using Angular CLI
- Copy AngularJS code
- Bootstrapping an hybrid application
- Set AngularJS as a global variable
- Include AngularJS route
- Fix errors
- Migrate the application’s features
- Adjust Routes
- 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:
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.
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:
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.scss
file. Here we can import any external style library:
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:
Import the app.module.ajs.js
into the main.ts
file:
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:
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:
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.
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:
Import the app.config.ajs.js
into the main.ts
file:
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 thephone.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/app
underassets
section onangular.json
thesrc/app
. Also modify thetemplateUrl
of thephone-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
andapp/phones
undersrc/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 insidephone.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:
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.
Replace the implementation of src/app/core/phone/phone.service.js
for an Angular class using typescript (rename to phone.service.ts
):
Downgrade the service so it could be used by AngularJS components:
Load thephone.service.ts
through the AppModule:
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:
Do the following changes in the html file:
- replace
.template.html
for.component.html
- replace
$ctrl
forvm
- replace AngularJS syntax to Angular (e.g. ng-repeat to *ngFor)
Do the same with phone-detail
.
Convert both components to typescript and make use of the Phone Service (already migrated to Angular):
Convert AngularJS component definition object into an Angular @Component
decorator:
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:
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
:
Update the phone-detail component to use the proper route:
Check the project’s code at this point.
10. Remove AngularJS
Remove AngularJS injection, the file main.ts
may return to the original code:
Remove all references to the UpgradeModule
from 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:
Add this <app-root>
element to the index.html
. It replaces the old AngularJS ng-view
directive:
Check the project’s code at this point. At this point we have the application migrated to the new version of Angular :)