angular-cn/modules/@angular/examples/upgrade/static/ts/module.ts

185 lines
7.2 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component, Directive, DoCheck, ElementRef, EventEmitter, Inject, Injectable, Injector, Input, NgModule, OnChanges, OnDestroy, OnInit, Output, SimpleChanges} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {UpgradeComponent, UpgradeModule, downgradeComponent, downgradeInjectable} from '@angular/upgrade/static';
interface Hero {
name: string;
description: string;
}
// #docregion Angular 2 Stuff
// #docregion ng2-heroes
// This Angular 2 component will be "downgraded" to be used in Angular 1
@Component({
selector: 'ng2-heroes',
// This template uses the upgraded `ng1-hero` component
// Note that because its element is compiled by Angular 2+ we must use camelCased attribute names
template: `<h1>Heroes</h1>
<p><ng-content></ng-content></p>
<div *ngFor="let hero of heroes">
<ng1-hero [hero]="hero" (onRemove)="removeHero.emit(hero)"><strong>Super Hero</strong></ng1-hero>
</div>
<button (click)="addHero.emit()">Add Hero</button>`,
})
class Ng2HeroesComponent {
@Input() heroes: Hero[];
@Output() addHero = new EventEmitter();
@Output() removeHero = new EventEmitter();
}
// #enddocregion
// #docregion ng2-heroes-service
// This Angular 2 service will be "downgraded" to be used in Angular 1
@Injectable()
class HeroesService {
heroes: Hero[] = [
{name: 'superman', description: 'The man of steel'},
{name: 'wonder woman', description: 'Princess of the Amazons'},
{name: 'thor', description: 'The hammer-wielding god'}
];
// #docregion use-ng1-upgraded-service
constructor(@Inject('titleCase') titleCase: (v: string) => string) {
// Change all the hero names to title case, using the "upgraded" Angular 1 service
this.heroes.forEach((hero: Hero) => hero.name = titleCase(hero.name));
}
// #enddocregion
addHero() {
this.heroes =
this.heroes.concat([{name: 'Kamala Khan', description: 'Epic shape-shifting healer'}]);
}
removeHero(hero: Hero) { this.heroes = this.heroes.filter((item: Hero) => item !== hero); }
}
// #enddocregion
// #docregion ng1-hero-wrapper
// This Angular 2 directive will act as an interface to the "upgraded" Angular 1 component
@Directive({selector: 'ng1-hero'})
class Ng1HeroComponentWrapper extends UpgradeComponent implements OnInit, OnChanges, DoCheck,
OnDestroy {
// The names of the input and output properties here must match the names of the
// `<` and `&` bindings in the Angular 1 component that is being wrapped
@Input() hero: Hero;
@Output() onRemove: EventEmitter<void>;
constructor(@Inject(ElementRef) elementRef: ElementRef, @Inject(Injector) injector: Injector) {
// We must pass the name of the directive as used by Angular 1 to the super
super('ng1Hero', elementRef, injector);
}
// For this class to work when compiled with AoT, we must implement these lifecycle hooks
// because the AoT compiler will not realise that the super class implements them
ngOnInit() { super.ngOnInit(); }
ngOnChanges(changes: SimpleChanges) { super.ngOnChanges(changes); }
ngDoCheck() { super.ngDoCheck(); }
ngOnDestroy() { super.ngOnDestroy(); }
}
// #enddocregion
// #docregion ng2-module
// This NgModule represents the Angular 2 pieces of the application
@NgModule({
declarations: [Ng2HeroesComponent, Ng1HeroComponentWrapper],
providers: [
HeroesService,
// #docregion upgrade-ng1-service
// Register an Angular 2+ provider whose value is the "upgraded" Angular 1 service
{provide: 'titleCase', useFactory: (i: any) => i.get('titleCase'), deps: ['$injector']}
// #enddocregion
],
// All components that are to be "downgraded" must be declared as `entryComponents`
entryComponents: [Ng2HeroesComponent],
// We must import `UpgradeModule` to get access to the Angular 1 core services
imports: [BrowserModule, UpgradeModule]
})
class Ng2AppModule {
ngDoBootstrap() { /* this is a placeholder to stop the boostrapper from complaining */
}
}
// #enddocregion
// #enddocregion
// #docregion Angular 1 Stuff
// #docregion ng1-module
// This Angular 1 module represents the Angular 1 pieces of the application
const ng1AppModule = angular.module('ng1AppModule', []);
// #enddocregion
// #docregion ng1-hero
// This Angular 1 component will be "upgraded" to be used in Angular 2+
ng1AppModule.component('ng1Hero', {
bindings: {hero: '<', onRemove: '&'},
transclude: true,
template: `<div class="title" ng-transclude></div>
<h2>{{ $ctrl.hero.name }}</h2>
<p>{{ $ctrl.hero.description }}</p>
<button ng-click="$ctrl.onRemove()">Remove</button>`
});
// #enddocregion
// #docregion ng1-title-case-service
// This Angular 1 service will be "upgraded" to be used in Angular 2+
ng1AppModule.factory(
'titleCase',
() => (value: string) => value.replace(/((^|\s)[a-z])/g, (_, c) => c.toUpperCase()));
// #enddocregion
// #docregion downgrade-ng2-heroes-service
// Register an Angular 1 service, whose value is the "downgraded" Angular 2+ injectable.
ng1AppModule.factory('heroesService', downgradeInjectable(HeroesService));
// #enddocregion
// #docregion ng2-heroes-wrapper
// This is directive will act as the interface to the "downgraded" Angular 2+ component
ng1AppModule.directive(
'ng2Heroes',
downgradeComponent(
// The inputs and outputs here must match the relevant names of the properties on the
// "downgraded" component
{component: Ng2HeroesComponent, inputs: ['heroes'], outputs: ['addHero', 'removeHero']}));
// #enddocregion
// #docregion example-app
// This is our top level application component
ng1AppModule.component('exampleApp', {
// We inject the "downgraded" HeroesService into this Angular 1 component
// (We don't need the `HeroesService` type for Angular 1 DI - it just helps with TypeScript
// compilation)
controller: [
'heroesService', function(heroesService: HeroesService) { this.heroesService = heroesService; }
],
// This template make use of the downgraded `ng2-heroes` component
// Note that because its element is compiled by Angular 1 we must use kebab-case attributes for
// inputs and outputs
template: `<link rel="stylesheet" href="./styles.css">
<ng2-heroes [heroes]="$ctrl.heroesService.heroes" (add-hero)="$ctrl.heroesService.addHero()" (remove-hero)="$ctrl.heroesService.removeHero($event)">
There are {{ $ctrl.heroesService.heroes.length }} heroes.
</ng2-heroes>`
});
// #enddocregion
// #enddocregion
// #docregion bootstrap
// First we bootstrap the Angular 2 HybridModule
// (We are using the dynamic browser platform as this example has not been compiled AoT)
platformBrowserDynamic().bootstrapModule(Ng2AppModule).then(ref => {
// Once Angular 2 bootstrap is complete then we bootstrap the Angular 1 module
const upgrade = ref.injector.get(UpgradeModule) as UpgradeModule;
upgrade.bootstrap(document.body, [ng1AppModule.name]);
});
// #enddocregion