Downgrading Angular 2 components to Angular 1 directives with downgradeComponent
If you have followed the steps in Connecting Angular 1 and Angular 2 with UpgradeModule, you should now have a hybrid application that is capable of sharing different elements with the opposing framework.
Tip
If you are unfamiliar with Angular 2 components, it is recommended that you go through the components chapter before you proceed.
This recipe will allow you to fully utilize Angular 2 components inside an Angular 1 template.
Note
The code, links, and a live example in relation to this recipe are available at http://ngcookbook.herokuapp.com/1499/.
Getting ready
Suppose you had the following Angular 2 component that you wanted to use in an Angular 1 application:
[app/article.component.ts] import {Component, Input} from '@angular/core'; @Component({ selector: 'ng2-article', template: ` <h1>{{title}}</h1> <p>Written by: {{author}}</p> ` }) export class ArticleComponent { @Input() author:string title:string = 'Unicycle Jousting Recognized as Olympic Sport'; }
Begin by completing the Connecting Angular 1 and Angular 2 with UpgradeModule recipe.
How to do it...
Angular 1 has no comprehension of how to utilize Angular 2 components. The existing Angular 2 framework will dutifully render it if given the opportunity, but the definition itself must be connected to the Angular 1 framework so that it may be requested when needed.
Begin by adding the component declarations to the module definition; this is used to link the two frameworks:
[app/app.module.ts] import {NgModule} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {UpgradeModule} from '@angular/upgrade/static'; import {RootComponent} from './root.component'; import {ArticleComponent} from './article.component'; @NgModule({ imports: [ BrowserModule, UpgradeModule, ], declarations: [ RootComponent, ArticleComponent ], bootstrap: [ RootComponent ] }) export class Ng2AppModule { constructor(public upgrade: UpgradeModule){} }
This connects the component declaration to the Angular 2 context, but Angular 1 still has no concept of how to interface with it. For this, you'll need to use downgradeComponent()
to define the Angular 2 component as an Angular 1 directive. Give the Angular 1 directive a different HTML tag to render inside so you can be certain that it's Angular 1 doing the rendering and not Angular 2:
[main.ts] import {Component, Input} from '@angular/core'; import {downgradeComponent} from '@angular/upgrade/static'; import {Ng1AppModule} from './ng1.module'; @Component({ selector: 'ng2-article', template: ` <h1>{{title}}</h1> <p>Written by: {{author}}</p> ` }) export class ArticleComponent { @Input() author:string title:string = 'Unicycle Jousting Recognized as Olympic Sport'; } Ng1AppModule.directive( 'ng1Article', downgradeComponent({component: ArticleComponent}));
Finally, since this component has an input, you'll need to pass this value via a binding attribute. Even though the component is still being declared as an Angular 1 directive, you'll use the Angular 2 binding syntax:
[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="authorName='Jake Hsu'">
<ng1-article [author]="authorName"></ng1-article>
</div>
<root></root>
</body>
</html>
The input and output must be explicitly declared at the time of conversion:
[app/article.component.ts]
import {Component, Input} from '@angular/core';
import {downgradeComponent} from '@angular/upgrade/static';
import {Ng1AppModule} from './ng1.module';
@Component({
selector: 'ng2-article',
template: `
<h1>{{title}}</h1>
<p>Written by: {{author}}</p>
`
})
export class ArticleComponent {
@Input() author:string
title:string = 'Unicycle Jousting Recognized as Olympic Sport';
}
Ng1AppModule.directive(
'ng1Article',
downgradeComponent({
component: ArticleComponent,
inputs: ['author']
}));
These are all the steps required. If done properly, you should see the component render along with the author's name being interpolated inside the Angular 2 component through Angular 1's ng-init
definition.
How it works...
You are giving Angular 1 the ability to direct Angular 2 to a certain element in the DOM and say, "I need you to render here." Angular 2 still controls the component view and operation, and in every sense, the main thing we really care about is a full Angular 2 component adapted for use in an Angular 1 template.
Tip
downgradeComponent()
takes an object specifying the component as an argument and returns the function that Angular 1 is expecting for the directive definition.
See also
- Connecting Angular 1 and Angular 2 with UpgradeModule shows you how to run Angular 1 and 2 frameworks together
- Downgrade Angular 2 providers to Angular 1 services with downgradeInjectable demonstrates how to use an Angular 2 service inside an Angular 1 application