Connecting Angular 1 and Angular 2 with UpgradeModule
Angular 2 comes with the ability to connect it to an existing Angular 1 application. This is obviously advantageous since this will allow you to utilize existing components and services in Angular 1 in tandem with Angular 2's components and services. UpgradeModule
is the tool that is supported by Angular teams to accomplish such a feat.
Note
The code, links, and a live example in relation to this recipe are available at http://ngcookbook.herokuapp.com/4137/.
Getting ready
Suppose you had a very simple Angular 1 application as follows:
[index.html] <!DOCTYPE html> <html> <head> <!-- Angular 1 scripts --> <script src="angular.js"></script> </head> <body> <div ng-app="hybridApp" ng-init="val='Angular 1 bootstrapped successfully!'"> {{val}} </div> </body> </html>
This application interpolates a value set in an Angular expression so you can visually confirm that the application has bootstrapped and is working.
How to do it...
Begin by declaring the top-level angular module inside its own file. Instead of using a script tag to fetch the angular module, require Angular 1, import it, and create the root Angular 1 module:
[ng1.module.ts] import 'angular' export const Ng1AppModule = angular.module('Ng1AppModule', []);
Angular 2 ships with an upgrade module out of the box, which is provided inside upgrade.js
. The two frameworks can be connected with UpgradeModule
.
Note
This recipe utilizes SystemJS and TypeScript, the specifications for which lie inside a very complicated config file. This is discussed in a later chapter, so don't worry about the specifics. For now, you are free to assume the following:
- SystemJS is configured to compile TypeScript (
.ts
) files on the fly - SystemJS is able to resolve the
import
andexport
statements in TypeScript files - SystemJS is able to resolve Angular 1 and 2 library imports
Angular 2 requires a top-level module definition as part of its base configuration:
[app/ng2.module.ts] import {NgModule} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {UpgradeModule} from '@angular/upgrade/static'; import {RootComponent} from './root.component'; @NgModule({ imports: [ BrowserModule, UpgradeModule, ], bootstrap: [ RootComponent ], declarations: [ RootComponent ] }) export class Ng2AppModule { constructor(public upgrade: UpgradeModule){} } export class AppModule {}
Tip
The reason why this module definition exists this way isn't critical for understanding this recipe. Angular 2 modules are covered in Chapter 7, Services, Dependency Injection, and NgModule.
Create the root component of the Angular 2 application:
[app/root.component.ts] import {Component} from '@angular/core'; @Component({ selector: 'root', template: ` <p>Angular 2 bootstrapped successfully!</p> ` }) export class RootComponent {}
Since Angular 2 will often bootstrap from a top-level file, create this file as main.ts
and bootstrap the Angular 2 module:
[main.ts] import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {Ng1AppModule} from './app/ng1.module'; import {Ng2AppModule} from './app/ng2.module'; platformBrowserDynamic() .bootstrapModule(Ng2AppModule);
Connecting Angular 1 to Angular 2
Don't use an ng-app to bootstrap the Angular 1 application; instead, do this after you bootstrap Angular 2:
[main.ts]
import {platformBrowserDynamic}
from '@angular/platform-browser-dynamic';
import {Ng1AppModule} from './app/ng1.module';
import {Ng2AppModule} from './app/ng2.module';
platformBrowserDynamic()
.bootstrapModule(Ng2AppModule)
.then(ref => {
ref.instance.upgrade
.bootstrap(document.body, [Ng1AppModule.name]);
});
With this, you'll be able to remove Angular 1's JS script, the ng-app
directive, and add in the root element of the Angular 2 app:
[index.html] <!DOCTYPE html> <html> <head> <!-- Angular 2 scripts --> <script src="zone.js "></script> <script src="reflect-metadata.js"></script> <script src="system.js"></script> <script src="system-config.js"></script> </head> <body> <div ng-init="val='Angular 1 bootstrapped successfully!'"> {{val}} </div> <root></root> </body> </html>
Note
The new scripts listed here are dependencies of an Angular 2 application, but understanding what they're doing isn't critical for understanding this recipe. This is explained later in the book.
With all this, you should see your Angular 1 application template compile and the Angular 2 component render properly again. This means that you are successfully running Angular 1 and Angular 2 frameworks side by side.
How it works...
Make no mistake, when you use UpgradeModule
, you create an Angular 1 and Angular 2 app on the same page and connect them together. This adapter instance will allow you to connect pieces from each framework and use them in harmony.
More specifically, this creates an Angular 1 application at the top level and allows you to uses pieces of an Angular 2 application inside it.
There's more...
While useful for experimentation and upgrading purposes, this should not be a solution that any application should rely on in a production context. You have effectively doubled the framework payload size and introduced additional complexity in an existing application. Although Angular 2 is a far more performant framework, do not expect to have the same pristine results with the UpgradeModule
cross-pollination.
That said, as you will see in subsequent recipes, you can now use Angular 2 components in an Angular 1 application using the adapter translation methods.
See also
- Downgrading Angular 2 components to Angular 1 directives with downgradeComponent demonstrates how to use an Angular 2 component inside an Angular 1 application
- Downgrade Angular 2 providers to Angular 1 services with downgradeInjectable, which demonstrates how to use an Angular 2 service inside an Angular 1 application