Upgrade from AngularJS to Angular 2

Requirements

About this tutorial

About our hybrid mobile app

Why you should upgrade?

Decide for an upgrade strategy

Preparation: AngularJS 1.5 or higher

Preparation: Layer application by feature/component

AngularJS application structure layered by feature

Upgrade baby step 1: Install and run Angular-CLI

npm install -g angular-cli
ng init
angular-cli init example

Upgrade baby step 2: Use .service() instead of .factory()

Upgrade baby step 3: bootstrap the AngularJS application in an Angular 2 environment

angular-cli.json example
Put the upgrade module into the src/app/shared folder
/**
* src/app/app.module.ts
*/
import { NgModule, forwardRef, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { DatePipe } from '@angular/common';
import { UrlHandlingStrategy } from '@angular/router';
import { BrowserModule } from '@angular/platform-browser';
import { UpgradeModule } from '@angular/upgrade/static';
import { UpgradeAdapter, UpgradeAdapterRef } from '@angular/upgrade';

import { AppCoreModule } from "./core/app-core.module";
import { AppComponent } from "./app.component";
import { APP_ROUTING } from "./app.routing";
import { Ng1UpgradeModule } from "./shared/upgrade/ng1-upgrade-shared.module";
import { Ng1Ng2UrlHandlingStrategy } from "./shared/upgrade/ng1-ng2-url-handling-strategy";

export const UPGRADE_ADAPTER = new UpgradeAdapter(forwardRef(() => AppModule));

/**
* Application base root module
*/
@NgModule({
imports: [
BrowserModule,
UpgradeModule,
Ng1UpgradeModule.forRoot(),
AppCoreModule,
APP_ROUTING,
],
declarations: [AppComponent],
bootstrap: [AppComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
exports: [],
providers: [
DatePipe,
{
provide: UrlHandlingStrategy,
useClass: Ng1Ng2UrlHandlingStrategy
}
]
})

export class AppModule {
ngDoBootstrap() {}
}
/**
* src/main.ts
*/
import './polyfills.ts';
import { enableProdMode, Inject } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { environment } from './environments/environment';
import { UpgradeModule } from '@angular/upgrade/static';
import { AppModule, UPGRADE_ADAPTER } from './app/app.module';
import { Ng1Ng2UpgradeSharedService } from "./app/shared/upgrade/ng1-upgrade-shared.service";


if (environment.production) {
enableProdMode();
}

// Bootstrap the application
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {

const upgradeSharedService = platformRef.injector.get(Ng1Ng2UpgradeSharedService);

// Bootstrap the application
UPGRADE_ADAPTER.bootstrap(document.documentElement, ['YOUR_NG1_APP_MODULE_NAME']).ready((upgradeAdapterRef) => {
upgradeSharedService.setUpgradeAdapterRef(upgradeAdapterRef);
});


});
/**
* src/app/app.component.ts
*/
import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.less']
})
export class AppComponent {
title = 'ng2 app works!';
}
<!-- Angular 2: Routed views go here -->
<router-outlet></router-outlet>

<!-- Angular 1: index.html content goes here -->
<div class="app">
<!-- App Body -->
<div id="app-body" class="app-body">
<div class="app-content" ng-class="direction">
<div class="modules-side-bar-container" ng-controller="NavBarController" >
<div ng-include="'assets/ui/html/shared/modules/modules-sidebar.html'"></div>
</div>
<ng-view></ng-view>

</div>
</div>
<div ui-yield-to="modals"></div>
<!doctype html>
<html>
<head>
<base href="/">
<meta charset="utf-8">
<title>Your Application Title</title>
</head>

<body>

<app-root>ng2 loading ...</app-root>

</body>
<!-- Angular 1 dependencies can also be defined here -->
<script src="assets/i18n/angular-locale_en-us.js"></script>
</html>

Upgrade baby step 4: AngularJS and Angular 2 routings

/**
* src/app/app.routing.ts
*/
import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AppComponent } from "./app.component";

const APP_ROUTES:Routes = [
{path: 'walkthrough', loadChildren: './walkthrough/walkthrough.module#WalkthroughModule'}
];

export const APP_ROUTING:ModuleWithProviders = RouterModule.forRoot(APP_ROUTES, {useHash: false, enableTracing: false, initialNavigation: true});
/**
* src/app/walkthrough/
walkthrough-routing.module.ts
*/
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { WalkthroughComponent } from "./walkthrough.component";

const routes:Routes = [
{path: '', component: WalkthroughComponent, children: []}
];

/**
* Walkthrough routings
*/
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
providers: []
})

export class WalkthroughRoutingModule {
}
/**
* src/app/shared/upgrade/
ng1-ng2-url-handling-strategy.ts
*/
import { UrlHandlingStrategy } from '@angular/router';

export class Ng1Ng2UrlHandlingStrategy implements UrlHandlingStrategy {

shouldProcessUrl(url) {
var urlStr:string = url.toString();
return urlStr == ("/") || urlStr == ("/auth") || urlStr == ("/login") || urlStr == ("/walkthrough");
}

extract(url) {
return url;
}

merge(url, whole) {
return url;
}
}

Verification: go through the following checklist before bootstrapping our partly migrated Angular 2 application

Let’s run the application

ng build
When you don’t have any errors the output should look like this
ng serve
http://localhost:4200
/**
* src/app/walkthrough/
walkthrough.component.ts
*/
import { Component, Inject } from '@angular/core';
import { Router } from '@angular/router';
import { DomSanitizer } from '@angular/platform-browser';

@Component({
selector: 'walkthrough',
templateUrl: './walkthrough.component.html',
styleUrls: ['./walkthrough.component.less']
})


export class WalkthroughComponent {
// is equivalent to $scope.walkthroughs
public walkthroughs:Array<IWalkthrough>;
// is equivalent to var name;
private name:string;
constructor(@Inject('$translate') private $translate:any,
private router:Router, sanitizer:DomSanitizer) {
// Data initialisation goes here to the constructor
this.
walkthroughs = [];
this.initTranslations();
}

/**
*
private functions are equivalent to the controller functions
*/
private initTranslations() {
// i.e. function initTranslations() {}
}

/**
*
public functions can be equivalent to the $scope functions
*/
callAPublicFunction
() {
// This public function can be called from the
// walkthrough.component.html file
}


}
/**
* src/app/walkthrough/walkthrough.module.ts
*/
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { CommonModule } from '@angular/common';

import { WalkthroughRoutingModule } from "./walkthrough-routing.module";
import { WalkthroughComponent } from "./walkthrough.component";
import { Ng1UpgradeModule } from "../shared/upgrade/ng1-upgrade-shared.module";

/**
* Walkthrough module
*/
@NgModule({
imports: [
Ng1UpgradeModule,
WalkthroughRoutingModule
],
declarations: [WalkthroughComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [],
exports: []
})


export class WalkthroughModule {
}
/**
*
ng1-upgrade-shared.providers.ts
*/
import {Ng1Ng2UpgradeSharedService} from "../upgrade/ng1-upgrade-shared.service";

export function upgradeTranslateFactory(upgradeAdapterRef:Ng1Ng2UpgradeSharedService) {
return upgradeAdapterRef.$injector.get("$translate");
}
/**
*
src/app/shared/ng1-upgrade-shared.module.ts
*/
import { NgModule } from '@angular/core';

import { Ng1Ng2UpgradeSharedService } from "./ng1-upgrade-shared.service";
import { TranslatePipe } from "./ng1-translate-shared.pipe";
import * as upgradeFactories from "./ng1-upgrade-shared.providers";

/**
* Ng1 Ng2 upgrade module
* Registers providers and AngularJS services, which can be injected in Angular 2 services or components.
*/
@NgModule({
declarations: [TranslatePipe],
exports: [TranslatePipe]
})


export class Ng1UpgradeModule {

static forRoot() {
return {
ngModule: Ng1UpgradeModule,
providers: [Ng1Ng2UpgradeSharedService,
{
provide: '$translate',
useFactory: upgradeFactories.upgradeTranslateFactory,
deps: [Ng1Ng2UpgradeSharedService]
}
]
}
}

}
/**
* src/app/shared/
ng1-translate-shared.pipe.ts
*/
import { Pipe, PipeTransform, Inject } from '@angular/core';

/**
* Translates AngularJS i18n translations.
*/
@Pipe({name: 'translate'})
export class TranslatePipe implements PipeTransform {

constructor(@Inject('$translate') private $translate:any) {}

transform(translationId:string) {
return this.$translate.instant(translationId);
}
}

A professional software engineer at Allianz (previously UBS). 10 years of experience in the IT industry. BSc in computer science at the University of London