docs(cb-ts-to-js): refactor sample code

This commit is contained in:
Ward Bell 2016-11-13 14:09:28 -08:00
parent b11438f211
commit 53f5538859
83 changed files with 1999 additions and 1749 deletions

View File

@ -1,4 +1,4 @@
'use strict'; // necessary for es6 output in node
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
@ -9,7 +9,7 @@ describe('TypeScript to Javascript tests', function () {
});
it('should display the basic component example', function () {
testTag('hero-view', 'Hero: Windstorm');
testTag('hero-view', 'Hero Detail: Windstorm');
});
it('should display the component example with lifecycle methods', function () {
@ -36,7 +36,7 @@ describe('TypeScript to Javascript tests', function () {
it('should support component with inputs and outputs', function () {
let app = element(by.css('hero-io'));
let confirmComponent = app.element(by.css('my-confirm'));
let confirmComponent = app.element(by.css('app-confirm'));
confirmComponent.element(by.buttonText('OK')).click();
expect(app.element(by.cssContainingText('span', 'OK clicked')).isPresent()).toBe(true);
@ -46,11 +46,11 @@ describe('TypeScript to Javascript tests', function () {
});
it('should support host bindings and host listeners', function() {
let app = element(by.css('heroes-bindings'));
let app = element(by.css('hero-host'));
let h1 = app.element(by.css('h1'));
expect(app.getAttribute('class')).toBe('heading');
expect(app.getAttribute('title')).toBe('Tooltip content');
expect(app.getAttribute('title')).toContain('Tooltip');
h1.click();
expect(h1.getAttribute('class')).toBe('active');
@ -61,12 +61,12 @@ describe('TypeScript to Javascript tests', function () {
});
it('should support content and view queries', function() {
let app = element(by.css('heroes-queries'));
let windstorm = app.element(by.css('a-hero:first-child'));
let app = element(by.css('hero-queries'));
let windstorm = app.element(by.css('view-child:first-child'));
app.element(by.buttonText('Activate')).click();
app.element(by.css('button')).click();
expect(windstorm.element(by.css('h2')).getAttribute('class')).toBe('active');
expect(windstorm.element(by.css('active-label')).getText()).toBe('Active');
expect(windstorm.element(by.css('content-child')).getText()).toBe('Active');
});
function testTag(selector: string, expectedText: string) {

View File

@ -0,0 +1,15 @@
import { Component } from '@angular/core';
@Component({
moduleId: module.id,
selector: 'my-app',
templateUrl: 'app.component.html',
styles: [
// See hero-di-inject-additional.component
'hero-host, hero-host-meta { border: 1px dashed black; display: block; padding: 4px;}',
'.heading {font-style: italic}'
]
})
export class AppComponent {
title = 'ES6 JavaScript with Decorators';
}

View File

@ -0,0 +1,31 @@
<a id="toc"></a>
<h1>{{title}}</h1>
<a href="#class-metadata">Classes and Class Metadata</a><br>
<a href="#io-metadata">Input and Output Decorators</a><br>
<a href="#dependency-injection">Dependency Injection</a><br>
<a href="#host-metadata">Host Metadata</a><br>
<a href="#view-child-metadata">View and Child Metadata</a><br>
<hr>
<h4 id="class-metadata">Classes and Class Metadata</h4>
<hero-view></hero-view>
<hero-lifecycle></hero-lifecycle>
<hr>
<h4 id="io-metadata">Input and Output Metadata</h4>
<hero-io></hero-io>
<hr>
<h4 id="dependency-injection">Dependency Injection</h4>
<hero-di></hero-di>
<hero-di-inject></hero-di-inject>
<hero-di-inject-additional></hero-di-inject-additional>
<hr>
<h4 id="host-metadata">Host Metadata</h4>
<hero-host></hero-host>
<hero-host-meta></hero-host-meta>
<hr>
<h4 id="view-child-metadata">View and Child Metadata</h4>
<hero-queries></hero-queries>

View File

@ -0,0 +1,55 @@
import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ConfirmComponent } from './confirm.component';
// #docregion appimport
import { HeroComponent } from './hero.component';
// #enddocregion appimport
import { HeroComponent as HeroDIComponent } from './hero-di.component';
import { HeroComponent as HeroDIInjectComponent } from './hero-di-inject.component';
import { HeroComponent as HeroDIInjectAdditionalComponent } from './hero-di-inject-additional.component';
import { HeroHostComponent } from './hero-host.component';
import { HeroHostMetaComponent } from './hero-host-meta.component';
import { HeroIOComponent } from './hero-io.component';
import { HeroComponent as HeroLifecycleComponent } from './hero-lifecycle.component';
import { HeroQueriesComponent, ViewChildComponent, ContentChildComponent } from './hero-queries.component';
import { HeroTitleComponent } from './hero-title.component';
import { DataService } from './data.service';
@NgModule({
imports: [
BrowserModule
],
declarations: [
AppComponent,
ConfirmComponent,
HeroComponent,
HeroDIComponent,
HeroDIInjectComponent,
HeroDIInjectAdditionalComponent,
HeroHostComponent, HeroHostMetaComponent,
HeroIOComponent,
HeroLifecycleComponent,
HeroQueriesComponent, ViewChildComponent, ContentChildComponent,
HeroTitleComponent
],
providers: [
DataService,
{ provide: 'heroName', useValue: 'Windstorm' }
],
bootstrap: [ AppComponent ],
// schemas: [ NO_ERRORS_SCHEMA ] // helpful for debugging
})
export class AppModule { }
/* tslint:disable no-unused-variable */
// #docregion ng2import
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import {
LocationStrategy,
HashLocationStrategy
} from '@angular/common';
// #enddocregion ng2import

View File

@ -0,0 +1,22 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
// #docregion
@Component({
moduleId: module.id,
selector: 'app-confirm',
templateUrl: 'confirm.component.html'
})
export class ConfirmComponent {
@Input() okMsg = '';
@Input('cancelMsg') notOkMsg = '';
@Output() ok = new EventEmitter();
@Output('cancel') notOk = new EventEmitter();
onOkClick() {
this.ok.emit(true);
}
onNotOkClick() {
this.notOk.emit(true);
}
}
// #enddocregion

View File

@ -2,8 +2,8 @@ import { Injectable } from '@angular/core';
@Injectable()
export class DataService {
constructor() {
}
constructor() { }
getHeroName() {
return 'Windstorm';
}

View File

@ -1,49 +1,7 @@
import {
Attribute,
Component,
Inject,
Optional,
NgModule
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
// #docregion
// #docregion metadata
@Component({
moduleId: module.id,
selector: 'hero-title',
templateUrl: 'title.component.html'
})
// #enddocregion metadata
class TitleComponent {
msg = '';
constructor(
@Inject('titlePrefix') @Optional() titlePrefix,
@Attribute('title') title
) {
this.titlePrefix = titlePrefix;
this.title = title;
}
ok() {
this.msg = 'OK!';
}
}
// #enddocregion
import { Component } from '@angular/core';
@Component({
selector: 'hero-di-inject-additional',
template: `<hero-title title="Tour of Heroes">
</hero-title>`
template: `<hero-title title="Tour of Heroes"></hero-title>`
})
class AppComponent { }
@NgModule({
imports: [ BrowserModule ],
declarations: [
AppComponent,
TitleComponent
],
bootstrap: [ AppComponent ]
})
export class HeroesDIInjectAdditionalModule { }
export class HeroComponent { }

View File

@ -1,22 +1,13 @@
import { Component, Inject, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component, Inject } from '@angular/core';
// #docregion
@Component({
selector: 'hero-di-inject',
template: `<h1>Hero: {{name}}</h1>`
})
class HeroComponent {
export class HeroComponent {
constructor(@Inject('heroName') name) {
this.name = name;
}
}
// #enddocregion
@NgModule({
imports: [ BrowserModule ],
providers: [ { provide: 'heroName', useValue: 'Windstorm' } ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
export class HeroesDIInjectModule { }

View File

@ -1,6 +1,4 @@
import { Component, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component } from '@angular/core';
import { DataService } from './data.service';
// #docregion
@ -8,19 +6,10 @@ import { DataService } from './data.service';
selector: 'hero-di',
template: `<h1>Hero: {{name}}</h1>`
})
class HeroComponent {
name;
export class HeroComponent {
name = '';
constructor(dataService: DataService) {
this.name = dataService.getHeroName();
}
}
// #enddocregion
@NgModule({
imports: [ BrowserModule ],
providers: [ DataService ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
export class HeroesDIModule { }

View File

@ -0,0 +1,44 @@
import { Component } from '@angular/core';
// #docregion
@Component({
selector: 'hero-host-meta',
template: `
<h1 [class.active]="active">Hero Host in Metadata</h1>
<div>Heading clicks: {{clicks}}</div>
`,
host: {
// HostBindings to the <hero-host-meta> element
'[title]': 'title',
'[class.heading]': 'headingClass',
// HostListeners on the entire <hero-host-meta> element
'(click)': 'clicked()',
'(mouseenter)': 'enter($event)',
'(mouseleave)': 'leave($event)'
},
// Styles within (but excluding) the <hero-host-meta> element
styles: ['.active {background-color: coral;}']
})
export class HeroHostMetaComponent {
title = 'Hero Host in Metadata Tooltip';
headingClass = true;
active = false;
clicks = 0;
clicked() {
this.clicks += 1;
}
enter(event: Event) {
this.active = true;
this.headingClass = false;
}
leave(event: Event) {
this.active = false;
this.headingClass = true;
}
}
// #enddocregion

View File

@ -0,0 +1,39 @@
import { Component, HostBinding, HostListener } from '@angular/core';
// #docregion
@Component({
selector: 'hero-host',
template: `
<h1 [class.active]="active">Hero Host in Decorators</h1>
<div>Heading clicks: {{clicks}}</div>
`,
// Styles within (but excluding) the <hero-host> element
styles: ['.active {background-color: yellow;}']
})
export class HeroHostComponent {
// HostBindings to the <hero-host> element
@HostBinding() title = 'Hero Host in Decorators Tooltip';
@HostBinding('class.heading') headingClass = true;
active = false;
clicks = 0;
// HostListeners on the entire <hero-host> element
@HostListener('click')
clicked() {
this.clicks += 1;
}
@HostListener('mouseenter', ['$event'])
enter(event: Event) {
this.active = true;
this.headingClass = false;
}
@HostListener('mouseleave', ['$event'])
leave(event: Event) {
this.active = false;
this.headingClass = true;
}
}
// #enddocregion

View File

@ -1,67 +1,26 @@
import {
Component,
EventEmitter,
Input,
Output,
NgModule
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
// #docregion
@Component({
moduleId: module.id,
selector: 'my-confirm',
templateUrl: 'confirm.component.html'
})
class ConfirmComponent {
@Input() okMsg;
@Input('cancelMsg') notOkMsg;
@Output() ok =
new EventEmitter();
@Output('cancel') notOk =
new EventEmitter();
onOkClick() {
this.ok.next(true);
}
onNotOkClick() {
this.notOk.next(true);
}
}
// #enddocregion
import { Component } from '@angular/core';
@Component({
selector: 'hero-io',
template: `
<my-confirm [okMsg]="'OK'"
[cancelMsg]="'Cancel'"
(ok)="onOk()"
(cancel)="onCancel()">
</my-confirm>
<app-confirm [okMsg]="'OK'"
[cancelMsg]="'Cancel'"
(ok)="onOk()"
(cancel)="onCancel()">
</app-confirm>
<span *ngIf="okClicked">OK clicked</span>
<span *ngIf="cancelClicked">Cancel clicked</span>
`
})
class AppComponent {
okClicked;
cancelClicked;
export class HeroIOComponent {
okClicked = false;
cancelClicked = false;
onOk() {
this.okClicked = true;
}
onCancel() {
this.cancelClicked = true;
}
}
@NgModule({
imports: [ BrowserModule ],
declarations: [
AppComponent,
ConfirmComponent
],
bootstrap: [ AppComponent ]
})
export class HeroesIOModule { }

View File

@ -1,27 +1,14 @@
// #docplaster
// #docregion
import { Component, OnInit } from '@angular/core';
// #enddocregion
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component } from '@angular/core';
@Component({
selector: 'hero-lifecycle',
template: `<h1>Hero: {{name}}</h1>`
})
// #docregion
class HeroComponent{
name;
export class HeroComponent {
name = '';
ngOnInit() {
this.name = 'Windstorm';
// todo: fetch from server async
setTimeout(() => this.name = 'Windstorm', 0);
}
}
// #enddocregion
@NgModule({
imports: [ BrowserModule ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
export class HeroesLifecycleModule { }

View File

@ -0,0 +1,81 @@
import {
Component,
ContentChild,
Input,
QueryList,
ViewChildren
} from '@angular/core';
@Component({
selector: 'content-child',
template: `
<span class="content-child" *ngIf="active">
Active
</span>`
})
export class ContentChildComponent {
active = false;
activate() {
this.active = true;
}
}
////////////////////
// #docregion content
@Component({
selector: 'view-child',
template: `
<h2 [class.active]=active>
{{hero.name}}
<ng-content></ng-content>
</h2>`,
styles: ['.active {font-weight: bold; background-color: skyblue;}']
})
export class ViewChildComponent {
@Input() hero;
active = false;
@ContentChild(ContentChildComponent) content;
activate() {
this.active = !this.active;
this.content.activate();
}
}
// #enddocregion content
////////////////////
// #docregion view
@Component({
selector: 'hero-queries',
template: `
<view-child *ngFor="let hero of heroData" [hero]="hero">
<content-child></content-child>
</view-child>
<button (click)="activate()">{{buttonLabel}} All</button>
`
})
export class HeroQueriesComponent {
active = false;
heroData = [
{id: 1, name: 'Windstorm'},
{id: 2, name: 'LaughingGas'}
];
@ViewChildren(ViewChildComponent) views;
activate() {
this.active = !this.active;
this.views.forEach(
view => view.activate()
);
}
get buttonLabel() {
return this.active ? 'Deactivate' : 'Activate';
}
}
// #enddocregion view

View File

@ -0,0 +1,26 @@
import { Attribute, Component, Inject, Optional } from '@angular/core';
// #docregion
// #docregion templateUrl
@Component({
moduleId: module.id,
selector: 'hero-title',
templateUrl: 'hero-title.component.html'
})
// #enddocregion templateUrl
export class HeroTitleComponent {
msg = '';
constructor(
@Inject('titlePrefix') @Optional() titlePrefix,
@Attribute('title') title
) {
this.titlePrefix = titlePrefix;
this.title = title;
}
ok() {
this.msg = 'OK!';
}
}
// #enddocregion

View File

@ -1,4 +1,3 @@
// #docplaster
// #docregion metadata
import { Component } from '@angular/core';
@ -6,24 +5,10 @@ import { Component } from '@angular/core';
selector: 'hero-view',
template: '<h1>{{title}}: {{getName()}}</h1>'
})
// #docregion appexport
// #docregion class
// #docregion appexport, class
export class HeroComponent {
title = 'Hero Detail';
getName() {return 'Windstorm'; }
}
// #enddocregion class
// #enddocregion appexport
// #enddocregion appexport, class
// #enddocregion metadata
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@NgModule({
imports: [ BrowserModule ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
export class HeroesModule { }

View File

@ -1,42 +0,0 @@
import {
Component,
HostBinding,
HostListener,
NgModule
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
// #docregion
@Component({
selector: 'heroes-bindings',
template: `
<h1 [class.active]="active">
Tour of Heroes
</h1>
`
})
class HeroesComponent {
@HostBinding() title = 'Tooltip content';
@HostBinding('class.heading') hClass = true;
active;
constructor() {}
@HostListener('click')
clicked() {
this.active = !this.active;
}
@HostListener('dblclick', ['$event'])
doubleClicked(evt) {
this.active = true;
}
}
// #enddocregion
@NgModule({
imports: [ BrowserModule ],
declarations: [ HeroesComponent ],
bootstrap: [ HeroesComponent ]
})
export class HeroesHostBindingsModule { }

View File

@ -1,88 +0,0 @@
import {
Component,
ViewChildren,
ContentChild,
QueryList,
Input,
NgModule
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@Component({
selector: 'active-label',
template: `<span class="active-label"
*ngIf="active">
Active
</span>`
})
class ActiveLabelComponent {
active;
activate() {
this.active = true;
}
}
// #docregion content
@Component({
selector: 'a-hero',
template: `<h2 [class.active]=active>
{{hero.name}}
<ng-content></ng-content>
</h2>`
})
class HeroComponent {
@Input() hero;
active;
@ContentChild(ActiveLabelComponent)
label;
activate() {
this.active = true;
this.label.activate();
}
}
// #enddocregion content
// #docregion view
@Component({
selector: 'heroes-queries',
template: `
<a-hero *ngFor="let hero of heroData"
[hero]="hero">
<active-label></active-label>
</a-hero>
<button (click)="activate()">
Activate
</button>
`
})
class HeroesQueriesComponent {
heroData = [
{id: 1, name: 'Windstorm'},
{id: 2, name: 'Superman'}
];
@ViewChildren(HeroComponent)
heroCmps;
activate() {
this.heroCmps.forEach(
(cmp) => cmp.activate()
);
}
}
// #enddocregion view
@NgModule({
imports: [ BrowserModule ],
declarations: [
HeroesQueriesComponent,
HeroComponent,
ActiveLabelComponent
],
bootstrap: [ HeroesQueriesComponent ]
})
export class HeroesQueriesModule { }

View File

@ -1,30 +1,4 @@
/* tslint:disable no-unused-variable */
// #docregion ng2import
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import {
LocationStrategy,
HashLocationStrategy
} from '@angular/common';
// #enddocregion ng2import
import { AppModule } from './app.module';
// #docregion appimport
import { HeroComponent } from './hero.component';
// #enddocregion appimport
import { HeroesModule } from './hero.component';
import { HeroesLifecycleModule } from './hero-lifecycle.component';
import { HeroesDIModule } from './hero-di.component';
import { HeroesDIInjectModule } from './hero-di-inject.component';
import { HeroesDIInjectAdditionalModule } from './hero-di-inject-additional.component';
import { HeroesIOModule } from './hero-io.component';
import { HeroesHostBindingsModule } from './heroes-bindings.component';
import { HeroesQueriesModule } from './heroes-queries.component';
platformBrowserDynamic().bootstrapModule(HeroesModule);
platformBrowserDynamic().bootstrapModule(HeroesLifecycleModule);
platformBrowserDynamic().bootstrapModule(HeroesDIModule);
platformBrowserDynamic().bootstrapModule(HeroesDIInjectModule);
platformBrowserDynamic().bootstrapModule(HeroesDIInjectAdditionalModule);
platformBrowserDynamic().bootstrapModule(HeroesIOModule);
platformBrowserDynamic().bootstrapModule(HeroesHostBindingsModule);
platformBrowserDynamic().bootstrapModule(HeroesQueriesModule);
platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -5,6 +5,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<title>TypeScript to JavaScript</title>
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
@ -20,32 +21,7 @@
</head>
<body>
<a id="toc"></a>
<h1>TypeScript to JavaScript</h1>
<a href="#class-metadata">Classes and Class Metadata</a><br>
<a href="#property-metadata">Input and Output Metadata</a><br>
<a href="#dependency-injection">Dependency Injection</a><br>
<a href="#other-property-metadata">Host and Query Metadata</a><br>
<hr>
<h4 id="class-metadata">Classes and Class Metadata</h4>
<hero-view id="class-metadata">Loading hero-view...</hero-view>
<hero-lifecycle>Loading hero-lifecycle...</hero-lifecycle>
<hr>
<h4 id="property-metadata">Input and Output Metadata</h4>
<hero-io>Loading hero-io...</hero-io>
<hr>
<h4 id="dependency-injection">Dependency Injection</h4>
<hero-di>Loading hero-di...</hero-di>
<hero-di-inject>Loading hero-di-inject...</hero-di-inject>
<hero-di-inject-additional>Loading hero-di-inject-additional...</hero-di-inject-additional>
<hr>
<h4 id="other-property-metadata">Host and Query Metadata</h4>
<heroes-bindings>Loading heroes-bindings...</heroes-bindings>
<heroes-queries id="other-property-metadata">Loading heroes-queries...</heroes-queries>
<my-app>Loading...</my-app>
</body>
</html>

View File

@ -0,0 +1,20 @@
import { Component } from '@angular/core';
export class AppComponent {
constructor() {
this.title = 'Plain ES6 JavaScript';
}
}
AppComponent.annotations = [
new Component({
moduleId: module.id,
selector: 'my-app',
templateUrl: 'app.component.html',
styles: [
// See hero-di-inject-additional.component
'hero-host { border: 1px dashed black; display: block; padding: 4px;}',
'.heading {font-style: italic}'
]
})
];

View File

@ -0,0 +1,30 @@
<a id="toc"></a>
<h1>{{title}}</h1>
<a href="#class-metadata">Classes and Class Metadata</a><br>
<a href="#io-metadata">Input and Output Metadata</a><br>
<a href="#dependency-injection">Dependency Injection</a><br>
<a href="#host-metadata">Host Metadata</a><br>
<a href="#view-child-metadata">View and Child Metadata</a><br>
<hr>
<h4 id="class-metadata">Classes and Class Metadata</h4>
<hero-view></hero-view>
<hero-lifecycle></hero-lifecycle>
<hr>
<h4 id="io-metadata">Input and Output Metadata</h4>
<hero-io></hero-io>
<hr>
<h4 id="dependency-injection">Dependency Injection</h4>
<hero-di></hero-di>
<hero-di-inject></hero-di-inject>
<hero-di-inject-additional></hero-di-inject-additional>
<hr>
<h4 id="host-metadata">Host Metadata</h4>
<hero-host></hero-host>
<hr>
<h4 id="view-child-metadata">View and Child Metadata</h4>
<hero-queries></hero-queries>

View File

@ -0,0 +1,56 @@
import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ConfirmComponent } from './confirm.component';
// #docregion appimport
import { HeroComponent } from './hero.component';
// #enddocregion appimport
import { HeroComponent as HeroDIComponent } from './hero-di.component';
import { HeroComponent as HeroDIInjectComponent } from './hero-di-inject.component';
import { HeroComponent as HeroDIInjectAdditionalComponent } from './hero-di-inject-additional.component';
import { HeroHostComponent } from './hero-host.component';
import { HeroIOComponent } from './hero-io.component';
import { HeroComponent as HeroLifecycleComponent } from './hero-lifecycle.component';
import { HeroQueriesComponent, ViewChildComponent, ContentChildComponent } from './hero-queries.component';
import { HeroTitleComponent } from './hero-title.component';
import { DataService } from './data.service';
export class AppModule { }
AppModule.annotations = [
new NgModule({
imports: [ BrowserModule],
declarations: [
AppComponent,
ConfirmComponent,
HeroComponent,
HeroDIComponent,
HeroDIInjectComponent,
HeroDIInjectAdditionalComponent,
HeroHostComponent,
HeroIOComponent,
HeroLifecycleComponent,
HeroQueriesComponent, ViewChildComponent, ContentChildComponent,
HeroTitleComponent
],
providers: [
DataService,
{ provide: 'heroName', useValue: 'Windstorm' }
],
bootstrap: [ AppComponent ],
// schemas: [ NO_ERRORS_SCHEMA ] // helpful for debugging
})
]
/* tslint:disable no-unused-variable */
// #docregion ng2import
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import {
LocationStrategy,
HashLocationStrategy
} from '@angular/common';
// #enddocregion ng2import

View File

@ -0,0 +1,32 @@
import { Component, EventEmitter } from '@angular/core';
// #docregion
export class ConfirmComponent {
constructor(){
this.ok = new EventEmitter();
this.notOk = new EventEmitter();
}
onOkClick() {
this.ok.emit(true);
}
onNotOkClick() {
this.notOk.emit(true);
}
}
ConfirmComponent.annotations = [
new Component({
moduleId: module.id,
selector: 'app-confirm',
templateUrl: 'confirm.component.html',
inputs: [
'okMsg',
'notOkMsg: cancelMsg'
],
outputs: [
'ok',
'notOk: cancel'
]
})
];
// #enddocregion

View File

@ -1,60 +1,10 @@
import {
Attribute,
Component,
Inject,
Optional,
NgModule
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component } from '@angular/core';
// #docregion
class TitleComponent {
constructor(titlePrefix, title) {
this.titlePrefix = titlePrefix;
this.title = title;
this.msg = '';
}
export class HeroComponent { }
ok() {
this.msg = 'OK!';
}
}
// #docregion metadata
TitleComponent.annotations = [
new Component({
moduleId: module.id,
selector: 'hero-title',
templateUrl: 'title.component.html'
})
];
// #enddocregion metadata
TitleComponent.parameters = [
[new Optional(), new Inject('titlePrefix')],
[new Attribute('title')]
];
// #enddocregion
class AppComponent {
}
AppComponent.annotations = [
HeroComponent.annotations = [
new Component({
selector: 'hero-di-inject-additional',
template: `<hero-title title="Tour of Heroes">
</hero-title>`
})
];
export class HeroesDIInjectAdditionalModule { }
HeroesDIInjectAdditionalModule.annotations = [
new NgModule({
imports: [ BrowserModule ],
declarations: [
AppComponent,
TitleComponent
],
bootstrap: [ AppComponent ]
template: `<hero-title title="Tour of Heroes"></hero-title>`
})
];

View File

@ -1,8 +1,7 @@
import { Component, Inject, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component, Inject } from '@angular/core';
// #docregion
class HeroComponent {
export class HeroComponent {
constructor(name) {
this.name = name;
}
@ -19,14 +18,3 @@ HeroComponent.parameters = [
[new Inject('heroName')]
];
// #enddocregion
export class HeroesDIInjectModule { }
HeroesDIInjectModule.annotations = [
new NgModule({
imports: [ BrowserModule ],
providers: [ { provide: 'heroName', useValue: 'Windstorm' } ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
];

View File

@ -1,10 +1,8 @@
import { Component, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component } from '@angular/core';
import { DataService } from './data.service';
// #docregion
class HeroComponent {
export class HeroComponent {
constructor(dataService) {
this.name = dataService.getHeroName();
}
@ -22,14 +20,3 @@ HeroComponent.parameters = [
];
// #enddocregion
export class HeroesDIModule { }
HeroesDIModule.annotations = [
new NgModule({
imports: [ BrowserModule ],
providers: [ DataService ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
];

View File

@ -0,0 +1,50 @@
import { Component } from '@angular/core';
// #docregion
export class HeroHostComponent {
constructor() {
this.active = false;
this.clicks = 0;
this.headingClass = true;
this.title = 'Hero Host Tooltip';
}
clicked() {
this.clicks += 1;
}
enter(event) {
this.active = true;
this.headingClass = false;
}
leave(event) {
this.active = false;
this.headingClass = true;
}
}
// #docregion metadata
HeroHostComponent.annotations = [
new Component({
selector: 'hero-host',
template: `
<h1 [class.active]="active">Hero Host</h1>
<div>Heading clicks: {{clicks}}</div>
`,
host: {
// HostBindings to the <hero-host> element
'[title]': 'title',
'[class.heading]': 'headingClass',
'(click)': 'clicked()',
// HostListeners on the entire <hero-host> element
'(mouseenter)': 'enter($event)',
'(mouseleave)': 'leave($event)'
},
// Styles within (but excluding) the <hero-host> element
styles: ['.active {background-color: yellow;}']
})
];
// #docregion metadata
// #enddocregion

View File

@ -1,79 +1,31 @@
import {
Component,
EventEmitter,
Input,
Output,
NgModule
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component } from '@angular/core';
// #docregion
class ConfirmComponent {
constructor(){
this.ok = new EventEmitter();
this.notOk = new EventEmitter();
export class HeroIOComponent {
constructor() {
this.okClicked = false;
this.cancelClicked = false;
}
onOkClick() {
this.ok.next(true);
}
onNotOkClick() {
this.notOk.next(true);
}
}
ConfirmComponent.annotations = [
new Component({
moduleId: module.id,
selector: 'my-confirm',
templateUrl: 'confirm.component.html',
inputs: [
'okMsg',
'notOkMsg: cancelMsg'
],
outputs: [
'ok',
'notOk: cancel'
]
})
];
// #enddocregion
class AppComponent {
constructor(){
}
onOk() {
this.okClicked = true;
}
onCancel() {
this.cancelClicked = true;
}
}
AppComponent.annotations = [
HeroIOComponent.annotations = [
new Component({
selector: 'hero-io',
template: `
<my-confirm [okMsg]="'OK'"
[cancelMsg]="'Cancel'"
(ok)="onOk()"
(cancel)="onCancel()">
</my-confirm>
<app-confirm [okMsg]="'OK'"
[cancelMsg]="'Cancel'"
(ok)="onOk()"
(cancel)="onCancel()">
</app-confirm>
<span *ngIf="okClicked">OK clicked</span>
<span *ngIf="cancelClicked">Cancel clicked</span>
`
})
];
export class HeroesIOModule { }
HeroesIOModule.annotations = [
new NgModule({
imports: [ BrowserModule ],
declarations: [
AppComponent,
ConfirmComponent
],
bootstrap: [ AppComponent ]
})
];

View File

@ -1,17 +1,11 @@
// #docplaster
// #docregion
import { Component } from '@angular/core';
// #enddocregion
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
// #docregion
class HeroComponent {
export class HeroComponent {
ngOnInit() {
this.name = 'Windstorm';
// todo: fetch from server async
setTimeout(() => this.name = 'Windstorm', 0);
}
}
// #enddocregion
HeroComponent.annotations = [
new Component({
@ -19,13 +13,3 @@ HeroComponent.annotations = [
template: `<h1>Hero: {{name}}</h1>`
})
];
export class HeroesLifecycleModule { }
HeroesLifecycleModule.annotations = [
new NgModule({
imports: [ BrowserModule ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
];

View File

@ -0,0 +1,97 @@
import {
Component,
ContentChild,
Input,
QueryList,
ViewChildren
} from '@angular/core';
export class ContentChildComponent {
constructor() {
this.active = false;
}
activate() {
this.active = !this.active;
}
}
ContentChildComponent.annotations = [
new Component({
selector: 'content-child',
template: `
<span class="content-child" *ngIf="active">
Active
</span>`
})
];
////////////////////
// #docregion content
export class ViewChildComponent {
constructor() {
this.active = false;
}
activate() {
this.active = !this.active;
this.content.activate();
}
}
ViewChildComponent.annotations = [
new Component({
selector: 'view-child',
template: `<h2 [class.active]=active>
{{hero.name}}
<ng-content></ng-content>
</h2>`,
styles: ['.active {font-weight: bold; background-color: skyblue;}'],
inputs: ['hero'],
queries: {
content: new ContentChild(ContentChildComponent)
}
})
];
// #enddocregion content
////////////////////
// #docregion view
export class HeroQueriesComponent {
constructor(){
this.active = false;
this.heroData = [
{id: 1, name: 'Windstorm'},
{id: 2, name: 'LaughingGas'}
];
}
activate() {
this.active = !this.active;
this.views.forEach(
view => view.activate()
);
}
get buttonLabel() {
return this.active ? 'Deactivate' : 'Activate';
}
}
HeroQueriesComponent.annotations = [
new Component({
selector: 'hero-queries',
template: `
<view-child *ngFor="let hero of heroData" [hero]="hero">
<content-child></content-child>
</view-child>
<button (click)="activate()">{{buttonLabel}} All</button>
`,
queries: {
views: new ViewChildren(ViewChildComponent)
}
})
];
// #enddocregion view

View File

@ -0,0 +1,29 @@
import { Attribute, Component, Inject, Optional } from '@angular/core';
// #docregion
export class HeroTitleComponent {
constructor(titlePrefix, title) {
this.titlePrefix = titlePrefix;
this.title = title;
this.msg = '';
}
ok() {
this.msg = 'OK!';
}
}
// #docregion templateUrl
HeroTitleComponent.annotations = [
new Component({
moduleId: module.id,
selector: 'hero-title',
templateUrl: 'hero-title.component.html'
})
];
// #enddocregion templateUrl
HeroTitleComponent.parameters = [
[new Optional(), new Inject('titlePrefix')],
[new Attribute('title')]
];

View File

@ -1,3 +1,4 @@
<!-- #docregion -->
<h1>{{titlePrefix}} {{title}}</h1>
<button (click)="ok()">OK</button>
<p>{{ msg }}</p>

View File

@ -2,16 +2,14 @@
// #docregion metadata
import { Component } from '@angular/core';
// #docregion class
// #docregion appexport
// #docregion appexport, class
export class HeroComponent {
constructor() {
this.title = 'Hero Detail';
}
getName() {return 'Windstorm'; }
}
// #enddocregion appexport
// #enddocregion class
// #enddocregion appexport, class
HeroComponent.annotations = [
new Component({
@ -20,18 +18,3 @@ HeroComponent.annotations = [
})
];
// #enddocregion metadata
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
export class HeroesModule { }
HeroesModule.annotations = [
new NgModule({
imports: [ BrowserModule ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
];

View File

@ -1,48 +0,0 @@
import {
Component,
HostBinding,
HostListener,
NgModule
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
// #docregion
class HeroesComponent {
constructor() {
this.title = 'Tooltip content';
this.hClass = true;
}
clicked() {
this.active = !this.active;
}
doubleClicked(evt) {
this.active = true;
}
}
HeroesComponent.annotations = [
new Component({
selector: 'heroes-bindings',
template: `<h1 [class.active]="active">
Tour of Heroes
</h1>`,
host: {
'[title]': 'title',
'[class.heading]': 'hClass',
'(click)': 'clicked()',
'(dblclick)': 'doubleClicked($event)'
}
})
];
// #enddocregion
export class HeroesHostBindingsModule { }
HeroesHostBindingsModule.annotations = [
new NgModule({
imports: [ BrowserModule ],
declarations: [ HeroesComponent ],
bootstrap: [ HeroesComponent ]
})
];

View File

@ -1,98 +0,0 @@
import {
Component,
ViewChildren,
ContentChild,
QueryList,
Input,
NgModule
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
class ActiveLabelComponent {
activate() {
this.active = true;
}
}
ActiveLabelComponent.annotations = [
new Component({
selector: 'active-label',
template: `
<span class="active-label" *ngIf="active">
Active
</span>`
})
];
// #docregion content
class HeroComponent {
activate() {
this.active = true;
this.label.activate();
}
}
HeroComponent.annotations = [
new Component({
selector: 'a-hero',
template: `<h2 [class.active]=active>
{{hero.name}}
<ng-content></ng-content>
</h2>`,
inputs: ['hero'],
queries: {
label: new ContentChild(ActiveLabelComponent)
}
})
];
// #enddocregion content
// #docregion view
class HeroesQueriesComponent {
constructor(){
this.heroData = [
{id: 1, name: 'Windstorm'},
{id: 2, name: 'Superman'}
];
}
activate() {
this.heroCmps.forEach(
(cmp) => cmp.activate()
);
}
}
HeroesQueriesComponent.annotations = [
new Component({
selector: 'heroes-queries',
template: `
<a-hero *ngFor="let hero of heroData"
[hero]="hero">
<active-label></active-label>
</a-hero>
<button (click)="activate()">
Activate
</button>
`,
queries: {
heroCmps: new ViewChildren(HeroComponent)
}
})
];
// #enddocregion view
export class HeroesQueriesModule { }
HeroesQueriesModule.annotations = [
new NgModule({
imports: [ BrowserModule ],
declarations: [
HeroesQueriesComponent,
HeroComponent,
ActiveLabelComponent
],
bootstrap: [ HeroesQueriesComponent ]
})
];

View File

@ -1,30 +1,4 @@
/* tslint:disable no-unused-variable */
// #docregion ng2import
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import {
LocationStrategy,
HashLocationStrategy
} from '@angular/common';
// #enddocregion ng2import
import { AppModule } from './app.module';
// #docregion appimport
import { HeroComponent } from './hero.component';
// #enddocregion appimport
import { HeroesModule } from './hero.component';
import { HeroesLifecycleModule } from './hero-lifecycle.component';
import { HeroesDIModule } from './hero-di.component';
import { HeroesDIInjectModule } from './hero-di-inject.component';
import { HeroesDIInjectAdditionalModule } from './hero-di-inject-additional.component';
import { HeroesIOModule } from './hero-io.component';
import { HeroesHostBindingsModule } from './heroes-bindings.component';
import { HeroesQueriesModule } from './heroes-queries.component';
platformBrowserDynamic().bootstrapModule(HeroesModule);
platformBrowserDynamic().bootstrapModule(HeroesLifecycleModule);
platformBrowserDynamic().bootstrapModule(HeroesDIModule);
platformBrowserDynamic().bootstrapModule(HeroesDIInjectModule);
platformBrowserDynamic().bootstrapModule(HeroesDIInjectAdditionalModule);
platformBrowserDynamic().bootstrapModule(HeroesIOModule);
platformBrowserDynamic().bootstrapModule(HeroesHostBindingsModule);
platformBrowserDynamic().bootstrapModule(HeroesQueriesModule);
platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -5,6 +5,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<title>TypeScript to JavaScript</title>
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
@ -20,33 +21,7 @@
</head>
<body>
<a id="toc"></a>
<h1>TypeScript to JavaScript</h1>
<a href="#class-metadata">Classes and Class Metadata</a><br>
<a href="#property-metadata">Input and Output Metadata</a><br>
<a href="#dependency-injection">Dependency Injection</a><br>
<a href="#other-property-metadata">Host and Query Metadata</a><br>
<my-app></my-app>
<hr>
<h4 id="class-metadata">Classes and Class Metadata</h4>
<hero-view id="class-metadata">Loading hero-view...</hero-view>
<hero-lifecycle>Loading hero-lifecycle...</hero-lifecycle>
<hr>
<h4 id="property-metadata">Input and Output Metadata</h4>
<hero-io>Loading hero-io...</hero-io>
<hr>
<h4 id="dependency-injection">Dependency Injection</h4>
<hero-di>Loading hero-di...</hero-di>
<hero-di-inject>Loading hero-di-inject...</hero-di-inject>
<hero-di-inject-additional>Loading hero-di-inject-additional...</hero-di-inject-additional>
<hr>
<h4 id="other-property-metadata">Host and Query Metadata</h4>
<heroes-bindings>Loading heroes-bindings...</heroes-bindings>
<heroes-queries id="other-property-metadata">Loading heroes-queries...</heroes-queries>
<my-app>Loading...</my-app>
</body>
</html>

View File

@ -0,0 +1,47 @@
<a id="toc"></a>
<h1>{{title}}</h1>
<a href="#class-metadata">Classes and Class Metadata</a><br>
<a href="#interfaces">Interfaces</a><br>
<a href="#io-metadata">Input and Output Metadata</a><br>
<a href="#dependency-injection">Dependency Injection</a><br>
<a href="#host-metadata">Host Metadata</a><br>
<a href="#view-child-metadata">View and Child Metadata</a><br>
<hr>
<h4 id="class-metadata">Classes and Class Metadata</h4>
<hero-view></hero-view>
<h4 id="class-metadata-dsl">Classes and Class Metadata (DSL)</h4>
<hero-view-dsl></hero-view-dsl>
<hr>
<h4 id="interfaces">Interfaces</h4>
<hero-lifecycle></hero-lifecycle>
<h4 id="interfaces-dsl">Interfaces (DSL)</h4>
<hero-lifecycle-dsl></hero-lifecycle-dsl>
<hr>
<h4 id="io-metadata">Input and Output Metadata</h4>
<hero-io></hero-io>
<h4 id="io-metadata-dsl">Input and Output Metadata (DSL)</h4>
<hero-io-dsl></hero-io-dsl>
<hr>
<h4 id="dependency-injection">Dependency Injection</h4>
<hero-di></hero-di>
<hero-di-inject></hero-di-inject>
<hero-di-inject-additional></hero-di-inject-additional>
<h4 id="dependency-injection-dsl">Dependency Injection (DSL)</h4>
<hero-di-dsl></hero-di-dsl>
<hero-di-inject-dsl></hero-di-inject-dsl>
<hero-di-inject-additional-dsl></hero-di-inject-additional-dsl>
<hr>
<h4 id="host-metadata">Host Metadata</h4>
<hero-host></hero-host>
<h4 id="host-metadata-dsl">Host Metadata (DSL)</h4>
<hero-host-dsl></hero-host-dsl>
<hr>
<h4 id="view-child-metadata">View and Child Metadata (DSL)</h4>
<hero-queries></hero-queries>

View File

@ -0,0 +1,20 @@
(function(app) {
app.AppComponent = AppComponent;
function AppComponent() {
this.title = 'ES5 JavaScript';
}
AppComponent.annotations = [
new ng.core.Component({
selector: 'my-app',
templateUrl: 'app/app.component.html',
styles: [
// See hero-di-inject-additional.component
'hero-host, hero-host-dsl { border: 1px dashed black; display: block; padding: 4px;}',
'.heading {font-style: italic}'
]
})
];
})(window.app = window.app || {});

View File

@ -0,0 +1,46 @@
(function(app) {
app.AppModule = AppModule;
function AppModule() { }
AppModule.annotations = [
new ng.core.NgModule({
imports: [ ng.platformBrowser.BrowserModule ],
declarations: [
app.AppComponent,
app.ConfirmComponent, app.ConfirmDslComponent,
app.HeroComponent, app.HeroDslComponent,
app.HeroDIComponent, app.HeroDIDslComponent,
app.HeroDIInjectComponent, app.HeroDIInjectDslComponent,
app.HeroDIInjectAdditionalComponent, app.HeroDIInjectAdditionalDslComponent,
app.HeroHostComponent, app.HeroHostDslComponent,
app.HeroIOComponent, app.HeroIODslComponent,
app.HeroLifecycleComponent, app.HeroLifecycleDslComponent,
app.heroQueries.HeroQueriesComponent, app.heroQueries.ViewChildComponent, app.heroQueries.ContentChildComponent,
app.HeroTitleComponent, app.HeroTitleDslComponent
],
providers: [
app.DataService,
{ provide: 'heroName', useValue: 'Windstorm' }
],
bootstrap: [ app.AppComponent ],
// schemas: [ ng.core.NO_ERRORS_SCHEMA ] // helpful for debugging!
})
]
})(window.app = window.app || {});
///// For documentation only /////
(function () {
// #docregion appimport
var HeroComponent = app.HeroComponent;
// #enddocregion appimport
// #docregion ng2import
var platformBrowserDynamic = ng.platformBrowserDynamic.platformBrowserDynamic;
var LocationStrategy = ng.common.LocationStrategy;
var HashLocationStrategy = ng.common.HashLocationStrategy;
// #enddocregion ng2import
})

View File

@ -0,0 +1,73 @@
(function(app) {
// #docregion
app.ConfirmComponent = ConfirmComponent;
ConfirmComponent.annotations = [
new ng.core.Component({
selector: 'app-confirm',
templateUrl: 'app/confirm.component.html',
inputs: [
'okMsg',
'notOkMsg: cancelMsg'
],
outputs: [
'ok',
'notOk: cancel'
]
})
];
function ConfirmComponent() {
this.ok = new ng.core.EventEmitter();
this.notOk = new ng.core.EventEmitter();
}
ConfirmComponent.prototype.onOkClick = function() {
this.ok.emit(true);
}
ConfirmComponent.prototype.onNotOkClick = function() {
this.notOk.emit(true);
}
// #enddocregion
})(window.app = window.app || {});
/////// DSL version ////////
(function(app) {
// #docregion dsl
app.ConfirmDslComponent = ng.core.Component({
selector: 'app-confirm-dsl',
templateUrl: 'app/confirm.component.html',
inputs: [
'okMsg',
'notOkMsg: cancelMsg'
],
outputs: [
'ok',
'notOk: cancel'
]
})
.Class({
constructor: function ConfirmDslComponent() {
this.ok = new ng.core.EventEmitter();
this.notOk = new ng.core.EventEmitter();
},
onOkClick: function() {
this.ok.emit(true);
},
onNotOkClick: function() {
this.notOk.emit(true);
}
});
// #enddocregion dsl
})(window.app = window.app || {});

View File

@ -1,13 +1,10 @@
(function(app) {
function DataService() {
}
DataService.annotations = [
new ng.core.Injectable()
];
app.DataService = DataService;
function DataService() { }
DataService.prototype.getHeroName = function() {
return 'Windstorm';
};
app.DataService = DataService;
})(window.app = window.app || {});

View File

@ -1,47 +1,26 @@
(function(app) {
// #docregion
// #docregion metadata
var TitleComponent = ng.core.Component({
selector: 'hero-title',
templateUrl: 'app/title.component.html'
})
// #enddocregion metadata
.Class({
constructor: [
[ new ng.core.Optional(), new ng.core.Inject('titlePrefix') ],
new ng.core.Attribute('title'),
function(titlePrefix, title) {
this.titlePrefix = titlePrefix;
this.title = title;
this.msg = '';
}
],
ok: function() {
this.msg = 'OK!';
}
});
// #enddocregion
app.HeroDIInjectAdditionalComponent = HeroDIInjectAdditionalComponent;
var AppComponent = ng.core.Component({
HeroDIInjectAdditionalComponent.annotations = [
new ng.core.Component({
selector: 'hero-di-inject-additional',
template: '<hero-title title="Tour of Heroes">' +
'</hero-title>'
}).Class({
constructor: function() { }
});
template: '<hero-title title="Tour of Heroes"></hero-title>'
})
];
app.HeroesDIInjectAdditionalModule =
ng.core.NgModule({
imports: [ ng.platformBrowser.BrowserModule ],
declarations: [
AppComponent,
TitleComponent
],
bootstrap: [ AppComponent ]
})
.Class({
constructor: function() {}
});
function HeroDIInjectAdditionalComponent() {}
})(window.app = window.app || {});
////// DSL Version /////////
(function(app) {
app.HeroDIInjectAdditionalDslComponent = ng.core.Component({
selector: 'hero-di-inject-additional-dsl',
template: '<hero-title-dsl title="Tour of Heroes"></hero-title-dsl>'
}).Class({
constructor: function HeroDIInjectAdditionalDslComponent() { }
});
})(window.app = window.app || {});

View File

@ -1,58 +1,41 @@
(function(app) {
// #docregion parameters
function HeroComponent(name) {
this.name = name;
}
HeroComponent.parameters = [
'heroName'
];
HeroComponent.annotations = [
new ng.core.Component({
selector: 'hero-di-inject',
template: '<h1>Hero: {{name}}</h1>'
})
];
// #enddocregion parameters
// #docregion
app.HeroDIInjectComponent = HeroDIInjectComponent;
app.HeroesDIInjectModule =
ng.core.NgModule({
imports: [ ng.platformBrowser.BrowserModule ],
providers: [ { provide: 'heroName', useValue: 'Windstorm' } ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
.Class({
constructor: function() {}
});
})(window.app = window.app || {});
(function(app) {
// #docregion ctor
var HeroComponent = ng.core.Component({
selector: 'hero-di-inline2',
HeroDIInjectComponent.annotations = [
new ng.core.Component({
selector: 'hero-di-inject',
template: '<h1>Hero: {{name}}</h1>'
})
.Class({
constructor: [
new ng.core.Inject('heroName'),
function(name) {
this.name = name;
}
]
});
// #enddocregion ctor
];
app.HeroesDIInjectModule2 =
ng.core.NgModule({
imports: [ ng.platformBrowser.BrowserModule ],
providers: [ { provide: 'heroName', useValue: 'Bombasto' } ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
.Class({
constructor: function() {}
});
HeroDIInjectComponent.parameters = [ 'heroName' ];
function HeroDIInjectComponent(name) {
this.name = name;
}
// #enddocregion
})(window.app = window.app || {});
/////// DSL version ////////
(function(app) {
// #docregion dsl
app.HeroDIInjectDslComponent = ng.core.Component({
selector: 'hero-di-inject-dsl',
template: '<h1>Hero: {{name}}</h1>'
})
.Class({
constructor: [
new ng.core.Inject('heroName'),
function HeroDIInjectDslComponent(name) {
this.name = name;
}
]
});
// #enddocregion dsl
})(window.app = window.app || {});

View File

@ -1,28 +0,0 @@
(function(app) {
// #docregion
var HeroComponent = ng.core.Component({
selector: 'hero-di-inline',
template: '<h1>Hero: {{name}}</h1>'
})
.Class({
constructor: [
app.DataService,
function(service) {
this.name = service.getHeroName();
}
]
});
// #enddocregion
app.HeroDIInlineModule =
ng.core.NgModule({
imports: [ ng.platformBrowser.BrowserModule ],
providers: [ app.DataService ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
.Class({
constructor: function() {}
});
})(window.app = window.app || {});

View File

@ -1,33 +1,43 @@
(function(app) {
// #docregion
app.HeroDIComponent = HeroComponent;
function HeroComponent(dataService) {
this.name = dataService.getHeroName();
}
HeroComponent.parameters = [
app.DataService
];
app.HeroDIComponent = HeroDIComponent;
HeroComponent.annotations = [
HeroDIComponent.annotations = [
new ng.core.Component({
selector: 'hero-di',
template: '<h1>Hero: {{name}}</h1>'
})
];
HeroDIComponent.parameters = [ app.DataService ];
function HeroDIComponent(dataService) {
this.name = dataService.getHeroName();
}
// #enddocregion
app.HeroesDIModule =
ng.core.NgModule({
imports: [ ng.platformBrowser.BrowserModule ],
providers: [ app.DataService ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
.Class({
constructor: function() {}
});
})(window.app = window.app || {});
////// DSL Version /////
(function(app) {
// #docregion dsl
app.HeroDIDslComponent = ng.core.Component({
selector: 'hero-di-dsl',
template: '<h1>Hero: {{name}}</h1>'
})
.Class({
constructor: [
app.DataService,
function HeroDIDslComponent(service) {
this.name = service.getHeroName();
}
]
});
// #enddocregion dsl
})(window.app = window.app || {});

View File

@ -1,29 +0,0 @@
// #docplaster
// #docregion appexport
(function(app) {
// #docregion component
var HeroComponent = ng.core.Component({
selector: 'hero-view-2',
template: '<h1>{{title}}: {{getName()}}</h1>',
})
.Class({
constructor: function() {
this.title = "Hero Detail";
},
getName: function() { return 'Windstorm'; }
});
// #enddocregion component
app.HeroesDslModule =
ng.core.NgModule({
imports: [ ng.platformBrowser.BrowserModule ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
.Class({
constructor: function() {}
});
})(window.app = window.app || {});
// #enddocregion appexport

View File

@ -0,0 +1,97 @@
(function(app) {
// #docregion
app.HeroHostComponent = HeroHostComponent;
HeroHostComponent.annotations = [
new ng.core.Component({
selector: 'hero-host',
template:
'<h1 [class.active]="active">Hero Host</h1>' +
'<div>Heading clicks: {{clicks}}</div>',
host: {
// HostBindings to the <hero-host> element
'[title]': 'title',
'[class.heading]': 'headingClass',
'(click)': 'clicked()',
// HostListeners on the entire <hero-host> element
'(mouseenter)': 'enter($event)',
'(mouseleave)': 'leave($event)'
},
// Styles within (but excluding) the <hero-host> element
styles: ['.active {background-color: yellow;}']
})
];
function HeroHostComponent() {
this.clicks = 0;
this.headingClass = true;
this.title = 'Hero Host Tooltip content';
}
HeroHostComponent.prototype.clicked = function() {
this.clicks += 1;
}
HeroHostComponent.prototype.enter = function(event) {
this.active = true;
this.headingClass = false;
}
HeroHostComponent.prototype.leave = function(event) {
this.active = false;
this.headingClass = true;
}
// #enddocregion
})(window.app = window.app || {});
//// DSL Version ////
(function(app) {
// #docregion dsl
app.HeroHostDslComponent = ng.core.Component({
selector: 'hero-host-dsl',
template: `
<h1 [class.active]="active">Hero Host (DSL)</h1>
<div>Heading clicks: {{clicks}}</div>
`,
host: {
// HostBindings to the <hero-host-dsl> element
'[title]': 'title',
'[class.heading]': 'headingClass',
'(click)': 'clicked()',
// HostListeners on the entire <hero-host-dsl> element
'(mouseenter)': 'enter($event)',
'(mouseleave)': 'leave($event)'
},
// Styles within (but excluding) the <hero-host-dsl> element
styles: ['.active {background-color: coral;}']
})
.Class({
constructor: function HeroHostDslComponent() {
this.clicks = 0;
this.headingClass = true;
this.title = 'Hero Host Tooltip DSL content';
},
clicked() {
this.clicks += 1;
},
enter(event) {
this.active = true;
this.headingClass = false;
},
leave(event) {
this.active = false;
this.headingClass = true;
}
});
// #enddocregion dsl
})(window.app = window.app || {});

View File

@ -0,0 +1,7 @@
<app-confirm-dsl [okMsg]="'OK'"
[cancelMsg]="'Cancel'"
(ok)="onOk()"
(cancel)="onCancel()">
</app-confirm-dsl>
<span *ngIf="okClicked">OK clicked</span>
<span *ngIf="cancelClicked">Cancel clicked</span>

View File

@ -0,0 +1,7 @@
<app-confirm [okMsg]="'OK'"
[cancelMsg]="'Cancel'"
(ok)="onOk()"
(cancel)="onCancel()">
</app-confirm>
<span *ngIf="okClicked">OK clicked</span>
<span *ngIf="cancelClicked">Cancel clicked</span>

View File

@ -1,62 +1,42 @@
(function(app) {
// #docregion
var ConfirmComponent = ng.core.Component({
selector: 'my-confirm',
templateUrl: 'app/confirm.component.html',
inputs: [
'okMsg',
'notOkMsg: cancelMsg'
],
outputs: [
'ok',
'notOk: cancel'
]
}).Class({
constructor: function() {
this.ok = new ng.core.EventEmitter();
this.notOk = new ng.core.EventEmitter();
},
onOkClick: function() {
this.ok.next(true);
},
onNotOkClick: function() {
this.notOk.next(true);
}
});
// #enddocregion
function AppComponent() {
}
AppComponent.annotations = [
new ng.core.Component({
selector: 'hero-io',
template: '<my-confirm [okMsg]="\'OK\'"' +
'[cancelMsg]="\'Cancel\'"' +
'(ok)="onOk()"' +
'(cancel)="onCancel()">' +
'</my-confirm>' +
'<span *ngIf="okClicked">OK clicked</span>' +
'<span *ngIf="cancelClicked">Cancel clicked</span>'
})
];
AppComponent.prototype.onOk = function() {
this.okClicked = true;
}
AppComponent.prototype.onCancel = function() {
this.cancelClicked = true;
}
app.HeroIOComponent = HeroComponent;
app.HeroesIOModule =
ng.core.NgModule({
imports: [ ng.platformBrowser.BrowserModule ],
declarations: [
AppComponent,
ConfirmComponent
],
bootstrap: [ AppComponent ]
})
.Class({
constructor: function() {}
});
HeroComponent.annotations = [
new ng.core.Component({
selector: 'hero-io',
templateUrl: 'app/hero-io.component.html'
})
];
function HeroComponent() { }
HeroComponent.prototype.onOk = function() {
this.okClicked = true;
}
HeroComponent.prototype.onCancel = function() {
this.cancelClicked = true;
}
})(window.app = window.app || {});
///// DSL Version ////
(function(app) {
app.HeroIODslComponent = ng.core.Component({
selector: 'hero-io-dsl',
templateUrl: 'app/hero-io-dsl.component.html'
})
.Class({
constructor: function HeroIODslComponent() { },
onOk: function() {
this.okClicked = true;
},
onCancel: function() {
this.cancelClicked = true;
}
});
})(window.app = window.app || {});

View File

@ -1,28 +1,42 @@
// #docplaster
(function(app) {
// #docregion
function HeroComponent() {}
// #enddocregion
HeroComponent.annotations = [
new ng.core.Component({
selector: 'hero-lifecycle',
template: '<h1>Hero: {{name}}</h1>'
})
];
// #docregion
HeroComponent.prototype.ngOnInit = function() {
this.name = 'Windstorm';
};
// #enddocregion
app.HeroesLifecycleModule =
ng.core.NgModule({
imports: [ ng.platformBrowser.BrowserModule ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
.Class({
constructor: function() {}
});
// #docregion
app.HeroLifecycleComponent = HeroComponent;
HeroComponent.annotations = [
new ng.core.Component({
selector: 'hero-lifecycle',
template: '<h1>Hero: {{name}}</h1>'
})
];
function HeroComponent() { }
HeroComponent.prototype.ngOnInit = function() {
// todo: fetch from server async
setTimeout(() => this.name = 'Windstorm', 0);
};
// #enddocregion
})(window.app = window.app || {});
/////// DSL version ////
(function(app) {
// #docregion dsl
app.HeroLifecycleDslComponent = ng.core.Component({
selector: 'hero-lifecycle-dsl',
template: '<h1>Hero: {{name}}</h1>'
})
.Class({
constructor: function HeroLifecycleDslComponent() { },
ngOnInit: function() {
// todo: fetch from server async
setTimeout(() => this.name = 'Windstorm', 0);
}
});
// #enddocregion dsl
})(window.app = window.app || {});

View File

@ -0,0 +1,92 @@
(function(app) {
app.heroQueries = app.heroQueries || {};
app.heroQueries.ContentChildComponent = ng.core.Component({
selector: 'content-child',
template:
'<span class="content-child" *ngIf="active">' +
'Active' +
'</span>'
}).Class({
constructor: function ContentChildComponent() {
this.active = false;
},
activate: function() {
this.active = !this.active;
}
});
////////////////////
// #docregion content
app.heroQueries.ViewChildComponent = ng.core.Component({
selector: 'view-child',
template:
'<h2 [class.active]=active>' +
'{{hero.name}} ' +
'<ng-content></ng-content>' +
'</h2>',
styles: ['.active {font-weight: bold; background-color: skyblue;}'],
inputs: ['hero'],
queries: {
content: new ng.core.ContentChild(app.heroQueries.ContentChildComponent)
}
})
.Class({
constructor: function HeroQueriesHeroComponent() {
this.active = false;
},
activate: function() {
this.active = !this.active;
this.content.activate();
}
});
// #enddocregion content
////////////////////
// #docregion view
app.heroQueries.HeroQueriesComponent = ng.core.Component({
selector: 'hero-queries',
template:
'<view-child *ngFor="let hero of heroData" [hero]="hero">' +
'<content-child></content-child>' +
'</view-child>' +
'<button (click)="activate()">{{buttonLabel}} All</button>',
queries: {
views: new ng.core.ViewChildren(app.heroQueries.ViewChildComponent)
}
})
.Class({
constructor: function HeroQueriesComponent() {
this.active = false;
this.heroData = [
{id: 1, name: 'Windstorm'},
{id: 2, name: 'LaughingGas'}
];
},
activate: function() {
this.active = !this.active;
this.views.forEach(function(view) {
view.activate();
});
},
});
// #docregion defined-property
// add prototype property w/ getter outside the DSL
var proto = app.heroQueries.HeroQueriesComponent.prototype;
Object.defineProperty(proto, "buttonLabel", {
get: function () {
return this.active ? 'Deactivate' : 'Activate';
},
enumerable: true
});
// #enddocregion defined-property
// #enddocregion view
})(window.app = window.app || {});

View File

@ -1,3 +1,4 @@
<!-- #docregion -->
<h1>{{titlePrefix}} {{title}}</h1>
<button (click)="ok()">OK</button>
<p>{{ msg }}</p>

View File

@ -0,0 +1,60 @@
(function(app) {
// #docregion
app.HeroTitleComponent = HeroTitleComponent;
// #docregion templateUrl
HeroTitleComponent.annotations = [
new ng.core.Component({
selector: 'hero-title',
templateUrl: 'app/hero-title.component.html'
})
];
// #enddocregion templateUrl
function HeroTitleComponent(titlePrefix, title) {
this.titlePrefix = titlePrefix;
this.title = title;
this.msg = '';
}
HeroTitleComponent.prototype.ok = function() {
this.msg = 'OK!';
}
HeroTitleComponent.parameters = [
[new ng.core.Optional(), new ng.core.Inject('titlePrefix')],
[new ng.core.Attribute('title')]
];
// #enddocregion
})(window.app = window.app || {});
////////// DSL version ////////////
(function(app) {
// #docregion dsl
app.HeroTitleDslComponent = ng.core.Component({
selector: 'hero-title-dsl',
templateUrl: 'app/hero-title.component.html'
})
.Class({
constructor: [
[ new ng.core.Optional(), new ng.core.Inject('titlePrefix') ],
new ng.core.Attribute('title'),
function HeroTitleDslComponent(titlePrefix, title) {
this.titlePrefix = titlePrefix;
this.title = title;
this.msg = '';
}
],
ok: function() {
this.msg = 'OK!';
}
});
// #enddocregion dsl
})(window.app = window.app || {});

View File

@ -1,38 +1,48 @@
// #docplaster
// #docregion appexport
(function(app) {
// #enddocregion appexport
// #docregion metadata
// #docregion appexport
// #docregion constructorproto
function HeroComponent() {
this.title = "Hero Detail";
}
HeroComponent.prototype.getName = function() { return 'Windstorm'; };
// #enddocregion constructorproto
// #docregion
// #docregion appexport
// #docregion metadata
app.HeroComponent = HeroComponent; // "export"
// #enddocregion appexport
HeroComponent.annotations = [
new ng.core.Component({
selector: 'hero-view',
template: '<h1>{{title}}: {{getName()}}</h1>'
})
];
// #enddocregion metadata
HeroComponent.annotations = [
new ng.core.Component({
selector: 'hero-view',
template: '<h1>{{title}}: {{getName()}}</h1>'
})
];
app.HeroesModule =
ng.core.NgModule({
imports: [ ng.platformBrowser.BrowserModule ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
.Class({
constructor: function() {}
});
// #docregion constructorproto
function HeroComponent() {
this.title = "Hero Detail";
}
// #docregion appexport
app.HeroComponent = HeroComponent;
HeroComponent.prototype.getName = function() { return 'Windstorm'; };
// #enddocregion constructorproto
// #enddocregion metadata
// #enddocregion appexport
// #enddocregion
})(window.app = window.app || {});
//////////// DSL version ///////////
(function(app) {
// #docregion dsl
app.HeroDslComponent = ng.core.Component({
selector: 'hero-view-dsl',
template: '<h1>{{title}}: {{getName()}}</h1>',
})
.Class({
constructor: function HeroDslComponent() {
this.title = "Hero Detail";
},
getName: function() { return 'Windstorm'; }
});
// #enddocregion dsl
})(window.app = window.app || {});
// #enddocregion appexport

View File

@ -1,39 +0,0 @@
(function(app) {
// #docregion
var HeroesComponent = ng.core.Component({
selector: 'heroes-bindings',
template: '<h1 [class.active]="active">' +
'Tour of Heroes' +
'</h1>',
host: {
'[title]': 'title',
'[class.heading]': 'hClass',
'(click)': 'clicked()',
'(dblclick)': 'doubleClicked($event)'
}
}).Class({
constructor: function() {
this.title = 'Tooltip content';
this.hClass = true;
},
clicked: function() {
this.active = !this.active;
},
doubleClicked: function(evt) {
this.active = true;
}
});
// #enddocregion
app.HeroesHostBindingsModule =
ng.core.NgModule({
imports: [ ng.platformBrowser.BrowserModule ],
declarations: [ HeroesComponent ],
bootstrap: [ HeroesComponent ]
})
.Class({
constructor: function() {}
});
})(window.app = window.app || {});

View File

@ -1,82 +0,0 @@
(function(app) {
var ActiveLabelComponent = ng.core.Component({
selector: 'active-label',
template: '<span class="active-label"' +
'*ngIf="active">' +
'Active' +
'</span>'
}).Class({
constructor: [function() { }],
activate: function() {
this.active = true;
}
});
// #docregion content
var HeroComponent = ng.core.Component({
selector: 'a-hero',
template: '<h2 [class.active]=active>' +
'{{hero.name}} ' +
'<ng-content></ng-content>' +
'</h2>',
inputs: ['hero'],
queries: {
label: new ng.core.ContentChild(
ActiveLabelComponent)
}
}).Class({
constructor: [function() { }],
activate: function() {
this.active = true;
this.label.activate();
}
});
app.HeroQueriesComponent = HeroComponent;
// #enddocregion content
// #docregion view
var AppComponent = ng.core.Component({
selector: 'heroes-queries',
template:
'<a-hero *ngFor="let hero of heroData"' +
'[hero]="hero">' +
'<active-label></active-label>' +
'</a-hero>' +
'<button (click)="activate()">' +
'Activate' +
'</button>',
queries: {
heroCmps: new ng.core.ViewChildren(
HeroComponent)
}
}).Class({
constructor: function() {
this.heroData = [
{id: 1, name: 'Windstorm'},
{id: 2, name: 'Superman'}
];
},
activate: function() {
this.heroCmps.forEach(function(cmp) {
cmp.activate();
});
}
});
// #enddocregion view
app.HeroesQueriesModule =
ng.core.NgModule({
imports: [ ng.platformBrowser.BrowserModule ],
declarations: [
AppComponent,
HeroComponent,
ActiveLabelComponent
],
bootstrap: [ AppComponent ]
})
.Class({
constructor: function() {}
});
})(window.app = window.app || {});

View File

@ -1,32 +1,9 @@
// #docplaster
// #docregion appimport
(function(app) {
// #enddocregion appimport
// #docregion ng2import
var platformBrowserDynamic = ng.platformBrowserDynamic.platformBrowserDynamic;
var LocationStrategy = ng.common.LocationStrategy;
var HashLocationStrategy = ng.common.HashLocationStrategy;
// #enddocregion ng2import
var platformBrowserDynamic = ng.platformBrowserDynamic.platformBrowserDynamic;
// #docregion appimport
var HeroComponent = app.HeroComponent;
// #enddocregion appimport
document.addEventListener('DOMContentLoaded', function() {
platformBrowserDynamic().bootstrapModule(app.AppModule);
});
document.addEventListener('DOMContentLoaded', function() {
platformBrowserDynamic().bootstrapModule(app.HeroesModule);
platformBrowserDynamic().bootstrapModule(app.HeroesDslModule);
platformBrowserDynamic().bootstrapModule(app.HeroesLifecycleModule);
platformBrowserDynamic().bootstrapModule(app.HeroesDIModule);
platformBrowserDynamic().bootstrapModule(app.HeroDIInlineModule);
platformBrowserDynamic().bootstrapModule(app.HeroesDIInjectModule);
platformBrowserDynamic().bootstrapModule(app.HeroesDIInjectModule2);
platformBrowserDynamic().bootstrapModule(app.HeroesDIInjectAdditionalModule);
platformBrowserDynamic().bootstrapModule(app.HeroesIOModule);
platformBrowserDynamic().bootstrapModule(app.HeroesHostBindingsModule);
platformBrowserDynamic().bootstrapModule(app.HeroesQueriesModule);
});
// #docregion appimport
})(window.app = window.app || {});
// #enddocregion appimport

View File

@ -4,12 +4,14 @@
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<title>TypeScript to JavaScript</title>
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<!-- Angular and RxJS umd scripts -->
<script src="node_modules/rxjs/bundles/Rx.js"></script>
<script src="node_modules/@angular/core/bundles/core.umd.js"></script>
<script src="node_modules/@angular/common/bundles/common.umd.js"></script>
@ -17,50 +19,26 @@
<script src="node_modules/@angular/platform-browser/bundles/platform-browser.umd.js"></script>
<script src="node_modules/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js"></script>
<!-- Application scripts -->
<script src="app/app.component.js"></script>
<script src="app/confirm.component.js"></script>
<script src="app/data.service.js"></script>
<script src="app/hero.component.js"></script>
<script src="app/hero-dsl.component.js"></script>
<script src="app/hero-lifecycle.component.js"></script>
<script src="app/hero-io.component.js"></script>
<script src="app/hero-di.component.js"></script>
<script src="app/hero-di-inline.component.js"></script>
<script src="app/hero-di-inject.component.js"></script>
<script src="app/hero-di-inject-additional.component.js"></script>
<script src="app/heroes-bindings.component.js"></script>
<script src="app/heroes-queries.component.js"></script>
<script src="app/hero-host.component.js"></script>
<script src="app/hero-lifecycle.component.js"></script>
<script src="app/hero-queries.component.js"></script>
<script src="app/hero-title.component.js"></script>
<script src="app/app.module.js"></script>
<script src="app/main.js"></script>
</head>
<body>
<a id="toc"></a>
<h1>TypeScript to JavaScript</h1>
<a href="#class-metadata">Classes and Class Metadata</a><br>
<a href="#property-metadata">Input and Output Metadata</a><br>
<a href="#dependency-injection">Dependency Injection</a><br>
<a href="#other-property-metadata">Host and Query Metadata</a><br>
<hr>
<h4 id="class-metadata">Classes and Class Metadata</h4>
<hero-view>Loading hero-view...</hero-view>
<hero-view-2>Loading hero-view2...</hero-view-2>
<hero-lifecycle>Loading hero-lifecycle...</hero-lifecycle>
<hr>
<h4 id="property-metadata">Input and Output Metadata</h4>
<hero-io>Loading hero-io...</hero-io>
<hr>
<h4 id="dependency-injection">Dependency Injection</h4>
<hero-di>Loading hero-di...</hero-di>
<hero-di-inline>Loading hero-di-inline...</hero-di-inline>
<hero-di-inline2>Loading hero-di-inline2...</hero-di-inline2>
<hero-di-inject>Loading hero-di-inject...</hero-di-inject>
<hero-di-inject-additional>Loading hero-di-inject-additional...</hero-di-inject-additional>
<hr>
<h4 id="other-property-metadata">Host and Query Metadata</h4>
<heroes-bindings>Loading heroes-bindings...</heroes-bindings>
<heroes-queries>Loading heroes-queries...</heroes-queries>
<my-app>Loading...</my-app>
</body>
</html>

View File

@ -0,0 +1,31 @@
<a id="toc"></a>
<h1>{{title}}</h1>
<a href="#class-metadata">Classes and Class Metadata</a><br>
<a href="#io-metadata">Input and Output Decorators</a><br>
<a href="#dependency-injection">Dependency Injection</a><br>
<a href="#host-metadata">Host Metadata</a><br>
<a href="#view-child-metadata">View and Child Metadata</a><br>
<hr>
<h4 id="class-metadata">Classes and Class Metadata</h4>
<hero-view></hero-view>
<hero-lifecycle></hero-lifecycle>
<hr>
<h4 id="io-metadata">Input and Output Metadata</h4>
<hero-io></hero-io>
<hr>
<h4 id="dependency-injection">Dependency Injection</h4>
<hero-di></hero-di>
<hero-di-inject></hero-di-inject>
<hero-di-inject-additional></hero-di-inject-additional>
<hr>
<h4 id="host-metadata">Host Metadata</h4>
<hero-host></hero-host>
<hero-host-meta></hero-host-meta>
<hr>
<h4 id="view-child-metadata">View and Child Metadata</h4>
<hero-queries></hero-queries>

View File

@ -0,0 +1,15 @@
import { Component } from '@angular/core';
@Component({
moduleId: module.id,
selector: 'my-app',
templateUrl: 'app.component.html',
styles: [
// See hero-di-inject-additional.component
'hero-host, hero-host-meta { border: 1px dashed black; display: block; padding: 4px;}',
'.heading {font-style: italic}'
]
})
export class AppComponent {
title = 'TypeScript';
}

View File

@ -0,0 +1,56 @@
/* tslint:disable-next-line:no-unused-variable */
import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ConfirmComponent } from './confirm.component';
// #docregion appimport
import { HeroComponent } from './hero.component';
// #enddocregion appimport
import { HeroComponent as HeroDIComponent } from './hero-di.component';
import { HeroComponent as HeroDIInjectComponent } from './hero-di-inject.component';
import { HeroComponent as HeroDIInjectAdditionalComponent } from './hero-di-inject-additional.component';
import { HeroHostComponent } from './hero-host.component';
import { HeroHostMetaComponent } from './hero-host-meta.component';
import { HeroIOComponent } from './hero-io.component';
import { HeroComponent as HeroLifecycleComponent } from './hero-lifecycle.component';
import { HeroQueriesComponent, ViewChildComponent, ContentChildComponent } from './hero-queries.component';
import { HeroTitleComponent } from './hero-title.component';
import { DataService } from './data.service';
@NgModule({
imports: [
BrowserModule
],
declarations: [
AppComponent,
ConfirmComponent,
HeroComponent,
HeroDIComponent,
HeroDIInjectComponent,
HeroDIInjectAdditionalComponent,
HeroHostComponent, HeroHostMetaComponent,
HeroIOComponent,
HeroLifecycleComponent,
HeroQueriesComponent, ViewChildComponent, ContentChildComponent,
HeroTitleComponent
],
providers: [
DataService,
{ provide: 'heroName', useValue: 'Windstorm' }
],
bootstrap: [ AppComponent ],
// schemas: [ NO_ERRORS_SCHEMA ] // helpful for debugging!
})
export class AppModule { }
/* tslint:disable no-unused-variable */
// #docregion ng2import
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import {
LocationStrategy,
HashLocationStrategy
} from '@angular/common';
// #enddocregion ng2import

View File

@ -0,0 +1,22 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
// #docregion
@Component({
moduleId: module.id,
selector: 'app-confirm',
templateUrl: 'confirm.component.html'
})
export class ConfirmComponent {
@Input() okMsg = '';
@Input('cancelMsg') notOkMsg = '';
@Output() ok = new EventEmitter();
@Output('cancel') notOk = new EventEmitter();
onOkClick() {
this.ok.emit(true);
}
onNotOkClick() {
this.notOk.emit(true);
}
}
// #enddocregion

View File

@ -2,8 +2,8 @@ import { Injectable } from '@angular/core';
@Injectable()
export class DataService {
constructor() {
}
constructor() { }
getHeroName() {
return 'Windstorm';
}

View File

@ -1,46 +1,7 @@
import {
Attribute,
Component,
Inject,
Optional,
NgModule
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
// #docregion
// #docregion metadata
@Component({
moduleId: module.id,
selector: 'hero-title',
templateUrl: 'title.component.html'
})
// #enddocregion metadata
class TitleComponent {
private msg: string = '';
constructor(
@Inject('titlePrefix') @Optional() private titlePrefix: string,
@Attribute('title') private title: string
) { }
ok() {
this.msg = 'OK!';
}
}
// #enddocregion
import { Component } from '@angular/core';
@Component({
selector: 'hero-di-inject-additional',
template: `<hero-title title="Tour of Heroes">
</hero-title>`
template: `<hero-title title="Tour of Heroes"></hero-title>`
})
class AppComponent { }
@NgModule({
imports: [ BrowserModule ],
declarations: [
AppComponent,
TitleComponent
],
bootstrap: [ AppComponent ]
})
export class HeroesDIInjectAdditionalModule { }
export class HeroComponent { }

View File

@ -1,20 +1,11 @@
import { Component, Inject, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component, Inject } from '@angular/core';
// #docregion
@Component({
selector: 'hero-di-inject',
template: `<h1>Hero: {{name}}</h1>`
})
class HeroComponent {
export class HeroComponent {
constructor(@Inject('heroName') private name: string) { }
}
// #enddocregion
@NgModule({
imports: [ BrowserModule ],
providers: [ { provide: 'heroName', useValue: 'Windstorm' } ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
export class HeroesDIInjectModule { }

View File

@ -1,6 +1,4 @@
import { Component, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component } from '@angular/core';
import { DataService } from './data.service';
// #docregion
@ -8,19 +6,10 @@ import { DataService } from './data.service';
selector: 'hero-di',
template: `<h1>Hero: {{name}}</h1>`
})
class HeroComponent {
name: string;
export class HeroComponent {
name = '';
constructor(dataService: DataService) {
this.name = dataService.getHeroName();
}
}
// #enddocregion
@NgModule({
imports: [ BrowserModule ],
providers: [ DataService ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
export class HeroesDIModule { }

View File

@ -0,0 +1,44 @@
import { Component } from '@angular/core';
// #docregion
@Component({
selector: 'hero-host-meta',
template: `
<h1 [class.active]="active">Hero Host in Metadata</h1>
<div>Heading clicks: {{clicks}}</div>
`,
host: {
// HostBindings to the <hero-host-meta> element
'[title]': 'title',
'[class.heading]': 'headingClass',
// HostListeners on the entire <hero-host-meta> element
'(click)': 'clicked()',
'(mouseenter)': 'enter($event)',
'(mouseleave)': 'leave($event)'
},
// Styles within (but excluding) the <hero-host-meta> element
styles: ['.active {background-color: coral;}']
})
export class HeroHostMetaComponent {
title = 'Hero Host in Metadata Tooltip';
headingClass = true;
active = false;
clicks = 0;
clicked() {
this.clicks += 1;
}
enter(event: Event) {
this.active = true;
this.headingClass = false;
}
leave(event: Event) {
this.active = false;
this.headingClass = true;
}
}
// #enddocregion

View File

@ -0,0 +1,39 @@
import { Component, HostBinding, HostListener } from '@angular/core';
// #docregion
@Component({
selector: 'hero-host',
template: `
<h1 [class.active]="active">Hero Host in Decorators</h1>
<div>Heading clicks: {{clicks}}</div>
`,
// Styles within (but excluding) the <hero-host> element
styles: ['.active {background-color: yellow;}']
})
export class HeroHostComponent {
// HostBindings to the <hero-host> element
@HostBinding() title = 'Hero Host in Decorators Tooltip';
@HostBinding('class.heading') headingClass = true;
active = false;
clicks = 0;
// HostListeners on the entire <hero-host> element
@HostListener('click')
clicked() {
this.clicks += 1;
}
@HostListener('mouseenter', ['$event'])
enter(event: Event) {
this.active = true;
this.headingClass = false;
}
@HostListener('mouseleave', ['$event'])
leave(event: Event) {
this.active = false;
this.headingClass = true;
}
}
// #enddocregion

View File

@ -1,67 +1,26 @@
import {
Component,
EventEmitter,
Input,
Output,
NgModule
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
// #docregion
@Component({
moduleId: module.id,
selector: 'my-confirm',
templateUrl: 'confirm.component.html'
})
class ConfirmComponent {
@Input() okMsg: string;
@Input('cancelMsg') notOkMsg: string;
@Output() ok =
new EventEmitter();
@Output('cancel') notOk =
new EventEmitter();
onOkClick() {
this.ok.next(true);
}
onNotOkClick() {
this.notOk.next(true);
}
}
// #enddocregion
import { Component } from '@angular/core';
@Component({
selector: 'hero-io',
template: `
<my-confirm [okMsg]="'OK'"
[cancelMsg]="'Cancel'"
(ok)="onOk()"
(cancel)="onCancel()">
</my-confirm>
<app-confirm [okMsg]="'OK'"
[cancelMsg]="'Cancel'"
(ok)="onOk()"
(cancel)="onCancel()">
</app-confirm>
<span *ngIf="okClicked">OK clicked</span>
<span *ngIf="cancelClicked">Cancel clicked</span>
`
})
class AppComponent {
okClicked: boolean;
cancelClicked: boolean;
export class HeroIOComponent {
okClicked = false;
cancelClicked = false;
onOk() {
this.okClicked = true;
}
onCancel() {
this.cancelClicked = true;
}
}
@NgModule({
imports: [ BrowserModule ],
declarations: [
AppComponent,
ConfirmComponent
],
bootstrap: [ AppComponent ]
})
export class HeroesIOModule { }

View File

@ -1,27 +1,14 @@
// #docplaster
// #docregion
import { Component, OnInit } from '@angular/core';
// #enddocregion
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@Component({
selector: 'hero-lifecycle',
template: `<h1>Hero: {{name}}</h1>`
})
// #docregion
class HeroComponent implements OnInit {
export class HeroComponent implements OnInit {
name: string;
ngOnInit() {
this.name = 'Windstorm';
// todo: fetch from server async
setTimeout(() => this.name = 'Windstorm', 0);
}
}
// #enddocregion
@NgModule({
imports: [ BrowserModule ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
export class HeroesLifecycleModule { }

View File

@ -0,0 +1,83 @@
import {
Component,
ContentChild,
Input,
QueryList,
ViewChildren
} from '@angular/core';
@Component({
selector: 'content-child',
template: `
<span class="content-child" *ngIf="active">
Active
</span>`
})
export class ContentChildComponent {
active = false;
activate() {
this.active = !this.active;
}
}
////////////////////
// #docregion content
@Component({
selector: 'view-child',
template: `
<h2 [class.active]=active>
{{hero.name}}
<ng-content></ng-content>
</h2>`,
styles: ['.active {font-weight: bold; background-color: skyblue;}']
})
export class ViewChildComponent {
@Input() hero: any;
active = false;
@ContentChild(ContentChildComponent) content: ContentChildComponent;
activate() {
this.active = !this.active;
this.content.activate();
}
}
// #enddocregion content
////////////////////
// #docregion view
@Component({
selector: 'hero-queries',
template: `
<view-child *ngFor="let hero of heroData" [hero]="hero">
<content-child></content-child>
</view-child>
<button (click)="activate()">{{buttonLabel}} All</button>
`
})
export class HeroQueriesComponent {
active = false;
heroData = [
{id: 1, name: 'Windstorm'},
{id: 2, name: 'LaughingGas'}
];
@ViewChildren(ViewChildComponent) views: QueryList<ViewChildComponent>;
activate() {
this.active = !this.active;
this.views.forEach(
view => view.activate()
);
}
// #docregion defined-property
get buttonLabel() {
return this.active ? 'Deactivate' : 'Activate';
}
// #enddocregion defined-property
}
// #enddocregion view

View File

@ -1,3 +1,4 @@
<!-- #docregion -->
<h1>{{titlePrefix}} {{title}}</h1>
<button (click)="ok()">OK</button>
<p>{{ msg }}</p>

View File

@ -0,0 +1,22 @@
import { Attribute, Component, Inject, Optional } from '@angular/core';
// #docregion
// #docregion templateUrl
@Component({
moduleId: module.id,
selector: 'hero-title',
templateUrl: 'hero-title.component.html'
})
// #enddocregion templateUrl
export class HeroTitleComponent {
msg: string = '';
constructor(
@Inject('titlePrefix') @Optional() private titlePrefix: string,
@Attribute('title') private title: string
) { }
ok() {
this.msg = 'OK!';
}
}
// #enddocregion

View File

@ -1,4 +1,3 @@
// #docplaster
// #docregion metadata
import { Component } from '@angular/core';
@ -6,24 +5,10 @@ import { Component } from '@angular/core';
selector: 'hero-view',
template: '<h1>{{title}}: {{getName()}}</h1>'
})
// #docregion appexport
// #docregion class
// #docregion appexport, class
export class HeroComponent {
title = 'Hero Detail';
getName() {return 'Windstorm'; }
}
// #enddocregion class
// #enddocregion appexport
// #enddocregion appexport, class
// #enddocregion metadata
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@NgModule({
imports: [ BrowserModule ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
export class HeroesModule { }

View File

@ -1,42 +0,0 @@
import {
Component,
HostBinding,
HostListener,
NgModule
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
// #docregion
@Component({
selector: 'heroes-bindings',
template: `
<h1 [class.active]="active">
Tour of Heroes
</h1>
`
})
class HeroesComponent {
@HostBinding() title = 'Tooltip content';
@HostBinding('class.heading') hClass = true;
active: boolean;
constructor() {}
@HostListener('click')
clicked() {
this.active = !this.active;
}
@HostListener('dblclick', ['$event'])
doubleClicked(evt: Event) {
this.active = true;
}
}
// #enddocregion
@NgModule({
imports: [ BrowserModule ],
declarations: [ HeroesComponent ],
bootstrap: [ HeroesComponent ]
})
export class HeroesHostBindingsModule { }

View File

@ -1,88 +0,0 @@
import {
Component,
ViewChildren,
ContentChild,
QueryList,
Input,
NgModule
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@Component({
selector: 'active-label',
template: `<span class="active-label"
*ngIf="active">
Active
</span>`
})
class ActiveLabelComponent {
active: boolean;
activate() {
this.active = true;
}
}
// #docregion content
@Component({
selector: 'a-hero',
template: `<h2 [class.active]=active>
{{hero.name}}
<ng-content></ng-content>
</h2>`
})
class HeroComponent {
@Input() hero: any;
active: boolean;
@ContentChild(ActiveLabelComponent)
label: ActiveLabelComponent;
activate() {
this.active = true;
this.label.activate();
}
}
// #enddocregion content
// #docregion view
@Component({
selector: 'heroes-queries',
template: `
<a-hero *ngFor="let hero of heroData"
[hero]="hero">
<active-label></active-label>
</a-hero>
<button (click)="activate()">
Activate
</button>
`
})
class HeroesQueriesComponent {
heroData = [
{id: 1, name: 'Windstorm'},
{id: 2, name: 'Superman'}
];
@ViewChildren(HeroComponent)
heroCmps: QueryList<HeroComponent>;
activate() {
this.heroCmps.forEach(
(cmp) => cmp.activate()
);
}
}
// #enddocregion view
@NgModule({
imports: [ BrowserModule ],
declarations: [
HeroesQueriesComponent,
HeroComponent,
ActiveLabelComponent
],
bootstrap: [ HeroesQueriesComponent ]
})
export class HeroesQueriesModule { }

View File

@ -1,30 +1,4 @@
/* tslint:disable no-unused-variable */
// #docregion ng2import
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import {
LocationStrategy,
HashLocationStrategy
} from '@angular/common';
// #enddocregion ng2import
// #docregion appimport
import { HeroComponent } from './hero.component';
// #enddocregion appimport
import { HeroesModule } from './hero.component';
import { HeroesLifecycleModule } from './hero-lifecycle.component';
import { HeroesDIModule } from './hero-di.component';
import { HeroesDIInjectModule } from './hero-di-inject.component';
import { HeroesDIInjectAdditionalModule } from './hero-di-inject-additional.component';
import { HeroesIOModule } from './hero-io.component';
import { HeroesHostBindingsModule } from './heroes-bindings.component';
import { HeroesQueriesModule } from './heroes-queries.component';
platformBrowserDynamic().bootstrapModule(HeroesModule);
platformBrowserDynamic().bootstrapModule(HeroesLifecycleModule);
platformBrowserDynamic().bootstrapModule(HeroesDIModule);
platformBrowserDynamic().bootstrapModule(HeroesDIInjectModule);
platformBrowserDynamic().bootstrapModule(HeroesDIInjectAdditionalModule);
platformBrowserDynamic().bootstrapModule(HeroesIOModule);
platformBrowserDynamic().bootstrapModule(HeroesHostBindingsModule);
platformBrowserDynamic().bootstrapModule(HeroesQueriesModule);
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -5,6 +5,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<title>TypeScript to JavaScript</title>
<!-- Polyfills for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
@ -20,32 +21,7 @@
</head>
<body>
<a id="toc"></a>
<h1>TypeScript to JavaScript</h1>
<a href="#class-metadata">Classes and Class Metadata</a><br>
<a href="#property-metadata">Input and Output Metadata</a><br>
<a href="#dependency-injection">Dependency Injection</a><br>
<a href="#other-property-metadata">Host and Query Metadata</a><br>
<hr>
<h4 id="class-metadata">Classes and Class Metadata</h4>
<hero-view id="class-metadata">Loading hero-view...</hero-view>
<hero-lifecycle>Loading hero-lifecycle...</hero-lifecycle>
<hr>
<h4 id="property-metadata">Input and Output Metadata</h4>
<hero-io>Loading hero-io...</hero-io>
<hr>
<h4 id="dependency-injection">Dependency Injection</h4>
<hero-di>Loading hero-di...</hero-di>
<hero-di-inject>Loading hero-di-inject...</hero-di-inject>
<hero-di-inject-additional>Loading hero-di-inject-additional...</hero-di-inject-additional>
<hr>
<h4 id="other-property-metadata">Host and Query Metadata</h4>
<heroes-bindings>Loading heroes-bindings...</heroes-bindings>
<heroes-queries id="other-property-metadata">Loading heroes-queries...</heroes-queries>
<my-app>Loading...</my-app>
</body>
</html>

View File

@ -15,19 +15,16 @@ a#toc
:marked
## Table of contents
[_TypeScript_ to _ES6_ to _ES5_](#from-ts)
[Modularity: imports and exports](#modularity)
[Classes and Class Metadata](#class-metadata)
[Input and Output Metadata](#property-metadata)
[Dependency Injection](#dependency-injection)
[Host and Query Metadata](#host-query-metadata)
[AoT compilation in _TypeScript_ Only](#aot)
[_TypeScript_ to _ES6_ to _ES5_](#from-ts)<br>
[Modularity: imports and exports](#modularity)<br>
[Classes and Class Metadata](#class-metadata)<br>
[_ES5_ DSL](#dsl)<br>
[Interfaces](#interfaces)<br>
[Input and Output Metadata](#io-decorators)<br>
[Dependency Injection](#dependency-injection)<br>
[Host Binding](#host-binding)<br>
[View and Child Decorators](#view-child-decorators)<br>
[AoT compilation in _TypeScript_ Only](#aot)<br>
**Run and compare the live <live-example name="cb-ts-to-js">_TypeScript_</live-example> and <live-example name="cb-ts-to-js" lang="js">JavaScript</live-example>
code shown in this cookbook.**
@ -38,7 +35,7 @@ a#from-ts
## _TypeScript_ to _ES6_ to _ES5_
_TypeScript_
<a href="https://www._TypeScript_lang.org" target="_blank" title='"TypeScript is a typed, superset of JavaScript"'>is a typed superset of _ES6 JavaScript_</a>.
<a href="https://www.typescriptlang.org" target="_blank" title='"TypeScript is a typed, superset of JavaScript"'>is a typed superset of _ES6 JavaScript_</a>.
&nbsp; _ES6 JavaScript_ is a superset of _ES5 JavaScript_. &nbsp; _ES5_ is the kind of JavaScript that runs natively in all modern browsers.
The transformation of _TypeScript_ code all the way down to _ES5_ code can be seen as "shedding" features.
@ -48,17 +45,17 @@ a#from-ts
* _ES6-without-decorators_ to _ES5_
When translating from _TypeScript_ to _ES6-with-decorators_, remove
[class property access modifiers](http://www._TypeScript_lang.org/docs/handbook/classes.html#public-private-and-protected-modifiers)
[class property access modifiers](http://www.typescriptlang.org/docs/handbook/classes.html#public-private-and-protected-modifiers)
such as `public` and `private`.
Remove most of the
[type annotations](https://www._TypeScript_lang.org/docs/handbook/basic-types.html),
such as `string` and `boolean`
but **keep type annotations used for dependency injection**.
[type declarations](https://www.typescriptlang.org/docs/handbook/basic-types.html),
such as `:string` and `:boolean`
but **keep the constructor parameter types which are used for dependency injection**.
From _ES6-with-decorators_ to _plain ES6_, remove all
[decorators](https://www._TypeScript_lang.org/docs/handbook/decorators.html)
and the remaining type annotations.
[decorators](https://www.typescriptlang.org/docs/handbook/decorators.html)
and the remaining types.
You must declare properties in the class constructor (`this.title = '...'`) rather than in the body of the class.
Finally, from _plain ES6_ to _ES5_, the main missing features are `import`
@ -82,24 +79,20 @@ a#modularity
In _ES5_, you access the Angular entities of the [the Angular packages](../glossary.html#!#scoped-package)
through the global `ng` object.
Everything you would have imported from `@angular` is a nested member of this `ng` object:
Anything you can import from `@angular` is a nested member of this `ng` object:
+makeTabs(`
cb-ts-to-js/ts/app/main.ts,
cb-ts-to-js/js-es6-decorators/app/main.es6,
cb-ts-to-js/js-es6/app/main.es6,
cb-ts-to-js/js/app/main.js
`,`
ng2import,
ng2import,
ng2import,
ng2import
`,`
TypeScript,
cb-ts-to-js/ts/app/app.module.ts,
cb-ts-to-js/js-es6-decorators/app/app.module.es6,
cb-ts-to-js/js-es6/app/app.module.es6,
cb-ts-to-js/js/app/app.module.js
`,
'ng2import,ng2import,ng2import,ng2import',
` TypeScript,
ES6 JavaScript with decorators,
ES6 JavaScript,
ES5 JavaScript
`)
`)(format='.')
:marked
### Exporting Application Code
@ -118,9 +111,9 @@ a#modularity
Add one application namespace object such as `app` to the global `document`.
Then each code file "exports" public entities by attaching them to that namespace object, e.g., `app.HeroComponent`.
You could factor a large application into several sub-namespaces
which leads to "exports" along the lines of `app.heroes.HeroComponent`.
which leads to "exports" along the lines of `app.heroQueries.HeroComponent`.
Every file should wrap _ES5_ code in an
Every _ES5_ file should wrap code in an
[Immediately Invoked Function Expression (IIFE)](https://en.wikipedia.org/wiki/Immediately-invoked_function_expression)
to limit unintentional leaking of private symbols into the global scope.
@ -131,13 +124,9 @@ a#modularity
cb-ts-to-js/js-es6-decorators/app/hero.component.es6,
cb-ts-to-js/js-es6/app/hero.component.es6,
cb-ts-to-js/js/app/hero.component.js
`,`
appexport,
appexport,
appexport,
appexport
`,`
TypeScript,
`,
'appexport,appexport,appexport,appexport',
` TypeScript,
ES6 JavaScript with decorators,
ES6 JavaScript,
ES5 JavaScript
@ -151,17 +140,13 @@ a#modularity
In _ES5_ you use the shared namespace object to access "exported" entities from other files.
+makeTabs(`
cb-ts-to-js/ts/app/main.ts,
cb-ts-to-js/js-es6-decorators/app/main.es6,
cb-ts-to-js/js-es6/app/main.es6,
cb-ts-to-js/js/app/main.js
`,`
appimport,
appimport,
appimport,
appimport
`,`
TypeScript,
cb-ts-to-js/ts/app/app.module.ts,
cb-ts-to-js/js-es6-decorators/app/app.module.es6,
cb-ts-to-js/js-es6/app/app.module.es6,
cb-ts-to-js/js/app/app.module.js
`,
'appimport,appimport,appimport,appimport',
` TypeScript,
ES6 JavaScript with decorators,
ES6 JavaScript,
ES5 JavaScript
@ -183,6 +168,20 @@ a#class-metadata
### Classes
Most Angular _TypeScript_ and _ES6_ code is written as classes.
Properties and method parameters of _TypeScript_ classes may be marked with the access modifiers
`private`, `internal`, and `public`.
Remove these modifiers when translating to JavaScript.
Most type declarations (e.g, `:string` and `:boolean`) should be removed when translating to JavaScript.
When translating to _ES6-with-decorators_, ***do not remove types from constructor parameters!***
Look for types in _TypeScript_ property declarations.
In general it is better to initialize such properties with default values because
many browser JavaScript engines can generate more performant code.
When _TypeScript_ code follows this same advice, it can infer the property types
and there is nothing to remove during translation.
In _ES6-without-decorators_, properties of classes must be assigned inside the constructor.
_ES5_ JavaScript has no classes.
@ -193,13 +192,9 @@ a#class-metadata
cb-ts-to-js/js-es6-decorators/app/hero.component.es6,
cb-ts-to-js/js-es6/app/hero.component.es6,
cb-ts-to-js/js/app/hero.component.js
`,`
class,
class,
class,
constructorproto
`,`
TypeScript,
`,
'class,class,class,constructorproto',
` TypeScript,
ES6 JavaScript with decorators,
ES6 JavaScript,
ES5 JavaScript
@ -226,13 +221,9 @@ a#class-metadata
cb-ts-to-js/js-es6-decorators/app/hero.component.es6,
cb-ts-to-js/js-es6/app/hero.component.es6,
cb-ts-to-js/js/app/hero.component.js
`,`
metadata,
metadata,
metadata,
metadata
`,`
TypeScript,
`,
'metadata,metadata,metadata,metadata',
` TypeScript,
ES6 JavaScript with decorators,
ES6 JavaScript,
ES5 JavaScript
@ -242,62 +233,95 @@ a#class-metadata
***External Template file***
A large component template is often kept in a separate template file.
+makeExample('cb-ts-to-js/ts/app/title.component.html', '', 'app/title.component.html')(format='.')
+makeExample('cb-ts-to-js/ts/app/hero-title.component.html', '', 'app/hero-title.component.html')(format='.')
:marked
The component (`TitleComponent` in this case) then references the template file in its metadata `templateUrl` property:
The component (`HeroTitleComponent` in this case) then references the template file in its metadata `templateUrl` property:
+makeTabs(`
cb-ts-to-js/ts/app/hero-di-inject-additional.component.ts,
cb-ts-to-js/js-es6-decorators/app/hero-di-inject-additional.component.es6,
cb-ts-to-js/js-es6/app/hero-di-inject-additional.component.es6,
cb-ts-to-js/js/app/hero-di-inject-additional.component.js`,
'metadata, metadata, metadata, metadata',
cb-ts-to-js/ts/app/hero-title.component.ts,
cb-ts-to-js/js-es6-decorators/app/hero-title.component.es6,
cb-ts-to-js/js-es6/app/hero-title.component.es6,
cb-ts-to-js/js/app/hero-title.component.js`,
'templateUrl, templateUrl, templateUrl, templateUrl',
`TypeScript,
ES6 JavaScript with decorators,
ES6 JavaScript,
ES5 JavaScript`)(format='.')
ES6 JavaScript with decorators,
ES6 JavaScript,
ES5 JavaScript
`)(format='.')
:marked
Note that the _TypeScript_ and both _ES6_ file `templateUrl` properties identify the location of the template file _relative to the component module_.
Note that the _TypeScript_ and both _ES6_ `templateUrl` properties identify the location of the template file _relative to the component module_.
All three metadata configurations specify the `moduleId` property
so that Angular can calculate the proper module address.
.l-sub-section
:marked
The `moduleId` may not be needed with certain tooling but it's safest to provide it anyway.
:marked
The _ES5_ approach shown here does not support modules and therefore there is no way to calculate a _module-relative URL_.
The `templateUrl` for the _ES5_ code must specify the _path from the project root_ and
omits the irrelevant `moduleId` property.
.l-sub-section
:marked
With the right tooling, the `moduleId` may not be needed in the other JavaScript dialects either.
But it's safest to provide it anyway.
***Angular class API***
a#dsl
.l-main-section
:marked
## _ES5_ DSL
This _ES5_ pattern of creating a constructor and annotating it with metadata is so common that Angular
provides a convenience API to make it a little more compact and locates the metadata above the constructor,
as you would if you wrote in _TypeScript_ or _ES6-with-decorators_.
Set a component variable to the result of an `ng.core.Component` function call.
This _API_ (_Application Programming Interface_) is commonly known as the _ES5 DSL_ (_Domain Specific Language_).
Set an application namespace property (e.g., `app.HeroDslComponent`) to the result of an `ng.core.Component` function call.
Pass the same metadata object to `ng.core.Component` as you did before.
Then chain a call to the `Class` method which takes an object defining the class constructor and instance methods.
Here is an example of the component class API next to the annotated function version for comparison:
Here is an example of the `HeroComponent`, re-written with the DSL,
next to the original _ES5_ version for comparison:
+makeTabs(`
cb-ts-to-js/js/app/hero-dsl.component.js,
cb-ts-to-js/js/app/hero.component.js,
cb-ts-to-js/js/app/hero.component.js
`,`
component,
metadata
`,`
ES5 JavaScript with Class API,
`,
'dsl,',
`
ES5 JavaScript with DSL,
ES5 JavaScript
`)
.callout.is-helpful
header Name the constructor
:marked
A **named** constructor displays clearly in the console log
if the component throws a runtime error.
An **unnamed** constructor displays as an anonymous function (e.g., `class0`)
which is impossible to find in the source code.
:marked
There are similar APIs for other decorated classes.
### Properties with getters and setters
_TypeScript_ and _ES6_ support with getters and setters.
Here's an example of a read-only _TypeScript_ property with a getter
that prepares a toggle-button label for the next clicked state:
+makeExample('cb-ts-to-js/ts/app/hero-queries.component.ts', 'defined-property', 'ts/app/hero-queries.component.ts')(format='.')
:marked
This _TypeScript_ "getter" property is transpiled to an _ES5_
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty"
target="_blank" title="Defined Properties">defined property</a>.
The _ES5 DSL_ does not support _defined properties_ directly
but you can still create them by extracting the "class" prototype and
adding the _defined property_ in raw JavaScript like this:
+makeExample('cb-ts-to-js/js/app/hero-queries.component.js', 'defined-property','js/app/hero-queries.component.ts')(format='.')
:marked
### DSL for other classes
There are similar DSLs for other decorated classes.
You can define a directive with `ng.core.Directive`:
code-example.
var MyDirective = ng.core.Directive({
app.MyDirective = ng.core.Directive({
selector: '[myDirective]'
}).Class({
...
@ -305,18 +329,20 @@ code-example.
:marked
and a pipe with `ng.core.Pipe`:
code-example.
var MyPipe = ng.core.Pipe({
app.MyPipe = ng.core.Pipe({
name: 'myPipe'
}).Class({
...
});
a#interfaces
.l-main-section
:marked
### Interfaces
## Interfaces
A _TypeScript_ interface helps ensure that a class implements the interface's members correctly.
We strongly recommend Angular interfaces where appropriate.
For example, a component that implements the `ngOnInit` lifecycle hook method
For example, the component class that implements the `ngOnInit` lifecycle hook method
should implement the `OnInit` interface.
_TypeScript_ interfaces exist for developer convenience and are not used by Angular at runtime.
@ -327,16 +353,18 @@ code-example.
cb-ts-to-js/ts/app/hero-lifecycle.component.ts,
cb-ts-to-js/js-es6-decorators/app/hero-lifecycle.component.es6,
cb-ts-to-js/js-es6/app/hero-lifecycle.component.es6,
cb-ts-to-js/js/app/hero-lifecycle.component.js,
cb-ts-to-js/js/app/hero-lifecycle.component.js
`,`
`,`
TypeScript,
`,
',,,,dsl',
` TypeScript,
ES6 JavaScript with decorators,
ES6 JavaScript,
ES5 JavaScript
ES5 JavaScript,
ES5 JavaScript with DSL
`)
a#property-metadata
a#io-decorators
.l-main-section
:marked
## Input and Output Metadata
@ -357,16 +385,18 @@ a#property-metadata
combined in the metadata `inputs` and `outputs` _arrays_.
+makeTabs(`
cb-ts-to-js/ts/app/hero-io.component.ts,
cb-ts-to-js/js-es6-decorators/app/hero-io.component.es6,
cb-ts-to-js/js-es6/app/hero-io.component.es6,
cb-ts-to-js/js/app/hero-io.component.js
`,`
`,`
TypeScript,
cb-ts-to-js/ts/app/confirm.component.ts,
cb-ts-to-js/js-es6-decorators/app/confirm.component.es6,
cb-ts-to-js/js-es6/app/confirm.component.es6,
cb-ts-to-js/js/app/confirm.component.js,
cb-ts-to-js/js/app/confirm.component.js
`,
',,,,dsl',
` TypeScript,
ES6 JavaScript with decorators,
ES6 JavaScript,
ES5 JavaScript
ES5 JavaScript,
ES5 JavaScript with DSL
`)
:marked
In the previous example, one of the public-facing binding names (`cancelMsg`)
@ -376,53 +406,76 @@ a#property-metadata
In _TypeScript_ and _ES6-with-decorators_,
you specify the special binding name in the argument to the property decorator.
In _ES5_ and _plain ES6_ code, convey this pairing with the `propertyName: bindingName` syntax in the class metadata.
.l-main-section
:marked
## Dependency Injection
Angular relies heavily on [Dependency Injection](../guide/dependency-injection.html) to provide services to the objects it creates.
When Angular creates a new component, directive, pipe or another service,
it sets the class constructor parameters to instances of services provided by an _Injector_.
### Injection by Type
The developer must tell Angular what to inject into each parameter.
Angular can often use _TypeScript_ type information to determine what needs to be injected.
_ES6-with-decorators_ can also make use of type information.
### Injection by Class Type
Since no type information is available in _ES5_/_ES6_ JavaScript, you must identify "injectables" in
some other way.
Attach a `parameters` array to the constructor function.
Each array item is the dependency injection token that identifies the thing to be injected.
Often the token is the constructor function for the class-like dependency.
The easiest and most popular technique in _TypeScript_ and _ES6-with-decorators_ is to set the constructor parameter type
to the class associated with the service to inject.
In _ES6_ the decorators need to be inside a nested array.
When writing in the _ES5_ class convenience API, you can supply the parameter tokens by wrapping
the constructor in an array.
The _TypeScript_ transpiler writes parameter type information into the generated JavaScript.
Angular reads that information at runtime and locates the corresponding service in the appropriate _Injector_..
The _ES6-with-decorators_ transpiler does essentially the same thing using the same parameter-typing syntax.
_ES5_ and _plain ES6_ lack types so you must identify "injectables" by attaching a **`parameters`** array to the constructor function.
Each item in the array specifies the service's injection token.
As with _TypeScript_ the most popular token is a class,
or rather a _constructor function_ that represents a class in _ES5_ and _plain ES6_.
The format of the `parameters` array varies:
* _plain ES6_ &mdash; nest each constructor function in a sub-array.
* _ES5_ &mdash; simply list the constructor functions.
When writing with _ES5 DSL_, set the `Class.constructor` property to
an array whose first parameters are the injectable constructor functions and whose
last parameter is the class constructor itself.
This format should be familiar to Angular 1 developers.
+makeTabs(`
cb-ts-to-js/ts/app/hero-di.component.ts,
cb-ts-to-js/js-es6-decorators/app/hero-di.component.es6,
cb-ts-to-js/js-es6/app/hero-di.component.es6,
cb-ts-to-js/js/app/hero-di.component.js,
cb-ts-to-js/js/app/hero-di-inline.component.js
`,`
`,`
TypeScript,
cb-ts-to-js/js/app/hero-di.component.js
`,
',,,,dsl',
` TypeScript,
ES6 JavaScript with decorators,
ES6 JavaScript,
ES5 JavaScript,
ES5 JavaScript with Class API
ES5 JavaScript with DSL
`)
:marked
### Injection with the @Inject decorator
When the thing being injected doesn't correspond directly to a type, you use the
`@Inject()` decorator to supply the injection token.
In this example, you are injecting a string identified by the "heroName" token.
Sometimes the dependency injection token isn't a class or constructor function.
In _TypeScript_ and _ES6-with-decorators_, you precede the class constructor parameter
by calling the `@Inject()` decorator with the injection token.
In the following example, the token is the string `'heroName'`.
In _ES5_/_ES6_ JavaScript you add the token string to the injection parameters array.
Alternatively, when using the _ES5_ convenience class API you can create a token with the
`Inject` method and add that to the constructor array in the annotations.
The other JavaScript dialogs add a `parameters` array to the class contructor function.
Each item constains a new instance of `Inject('heroName')`:
* _plain ES6_ &mdash; each item is a new instance of `Inject(token)` in a sub-array.
* _ES5_ &mdash; simply list the string tokens.
When writing with _ES5 DSL_, set the `Class.constructor` property to a function definition
array as before. Create a `new ng.core.Inject(token)` for each parameter.
+makeTabs(`
cb-ts-to-js/ts/app/hero-di-inject.component.ts,
@ -430,67 +483,74 @@ a#property-metadata
cb-ts-to-js/js-es6/app/hero-di-inject.component.es6,
cb-ts-to-js/js/app/hero-di-inject.component.js,
cb-ts-to-js/js/app/hero-di-inject.component.js
`,`
,
,
,
parameters,
ctor
`,`
TypeScript,
`,
',,,,dsl',
` TypeScript,
ES6 JavaScript with decorators,
ES6 JavaScript,
ES5 JavaScript,
ES5 JavaScript with Class API
ES5 JavaScript with DSL
`)
:marked
### Additional Injection Decorators
You can attach additional decorators to constructor parameters to qualify the injection behavior.
You can mark optional dependencies with the [`@Optional`](../api/core/index/Optional-decorator.html),
inject host element attributes with [`@Attribute`](../api/core/index/Attribute-interface.html),
inject content child queries with [`@ContentChild`](../api/core/index/ContentChild-decorator.html)
and inject view child queries with [`@ViewChild`](../api/core/index/ViewChild-decorator.html)).
You can qualify injection behavior with injection decorators from `@angular/core`.
In ES6 JavaScript you just add the extra decorators to the nested injection parameters array.
In _TypeScript_ and _ES6-with-decorators_,
you precede the constructor parameters with injection qualifiers such as:
* [`@Optional`](../api/core/index/Optional-decorator.html) sets the parameter to `null` if the service is missing
* [`@Attribute`](../api/core/index/Attribute-interface.html) to inject a host element attribute value
* [`@ContentChild`](../api/core/index/ContentChild-decorator.html) to inject a content child
* [`@ViewChild`](../api/core/index/ViewChild-decorator.html) to inject a view child
* [`@Host`](../api/core/index/Host-decorator.html) to inject a service in this component or its host
* [`@SkipSelf`](../api/core/index/SkipSelf-decorator.html) to inject a service provided in an ancestor of this component
To achieve the same effect in _ES5_ JavaScript, use a nested array with the constructor
array notation in which the injection information precedes the constructor function itself.
In _plain ES6_ and _ES5_, create an instance of the equivalent injection qualifier in a nested array within the `parameters` array.
For example, you'd write `new Optional()` in _plain ES6_ and `new ng.core.Optional()` in _ES5_.
You can apply other additional parameter decorators such as
[`@Host`](../api/core/index/Host-decorator.html) and
[`@SkipSelf`](../api/core/index/SkipSelf-decorator.html) in the same way -
by adding `new ng.core.Host()` or `ng.core.SkipSelf()` in the
parameters array.
When writing with _ES5 DSL_, set the `Class.constructor` property to a function definition
array as before. Use a nested array to define a parameter's complete injection specification.
+makeTabs(`
cb-ts-to-js/ts/app/hero-di-inject-additional.component.ts,
cb-ts-to-js/js-es6-decorators/app/hero-di-inject-additional.component.es6,
cb-ts-to-js/js-es6/app/hero-di-inject-additional.component.es6,
cb-ts-to-js/js/app/hero-di-inject-additional.component.js
`,`
`,`
TypeScript,
cb-ts-to-js/ts/app/hero-title.component.ts,
cb-ts-to-js/js-es6-decorators/app/hero-title.component.es6,
cb-ts-to-js/js-es6/app/hero-title.component.es6,
cb-ts-to-js/js/app/hero-title.component.js,
cb-ts-to-js/js/app/hero-title.component.js
`,
',,,,dsl',
` TypeScript,
ES6 JavaScript with decorators,
ES6 JavaScript,
ES5 JavaScript
`)
ES5 JavaScript,
ES5 JavaScript with DSL
`)
.l-sub-section
:marked
In the example above, there is no provider for the `'titlePrefix'` token.
Without `Optional`, Angular would raise an error.
With `Optional`, Angular sets the constructor parameter to `null`
and the component displays the title without a prefix.
a#host-query-metadata
a#host-binding
.l-main-section
:marked
## Host and Query Metadata
## Host Binding
Angular supports bindings to properties and events of the _host element_ which is the
element whose tag matches the component selector.
### Host Decorators
In _TypeScript_ and _ES6-with-decorators_ you can use host property decorators to bind a host
In _TypeScript_ and _ES6-with-decorators_, you can use host property decorators to bind a host
element to a component or directive.
The [`@HostBinding`](../api/core/index/HostBinding-interface.html) decorator
binds host element properties to component data properties.
The [`@HostListener`](../api/core/index/HostListener-interface.html) decorator binds
host element events to component event handlers.
When using _ES5_/_ES6_, add a `host` attribute to the component metadata to achieve the
In _plain ES6_ or _ES5_, add a `host` attribute to the component metadata to achieve the
same effect as `@HostBinding` and `@HostListener`.
The `host` value is an object whose properties are host property and listener bindings:
@ -500,54 +560,74 @@ a#host-query-metadata
* Each value identifies the corresponding component property or method.
+makeTabs(`
cb-ts-to-js/ts/app/heroes-bindings.component.ts,
cb-ts-to-js/js-es6-decorators/app/heroes-bindings.component.es6,
cb-ts-to-js/js-es6/app/heroes-bindings.component.es6,
cb-ts-to-js/js/app/heroes-bindings.component.js
`,`
`,`
TypeScript,
cb-ts-to-js/ts/app/hero-host.component.ts,
cb-ts-to-js/js-es6-decorators/app/hero-host.component.es6,
cb-ts-to-js/js-es6/app/hero-host.component.es6,
cb-ts-to-js/js/app/hero-host.component.js,
cb-ts-to-js/js/app/hero-host.component.js
`,
',,,,dsl',
` TypeScript,
ES6 JavaScript with decorators,
ES6 JavaScript,
ES5 JavaScript
ES5 JavaScript,
ES5 JavaScript with DSL
`)
.alert.is-helpful
:marked
In _TypeScript_ and _ES6-with-decorators_ you can also use the `queries` metadata
instead of the `@ViewChild` and `@ContentChild` property decorators.
:marked
### Query Decorators
### Host Metadata
Some developers prefer to specify host properties and listeners
in the component metadata.
They'd _rather_ do it the way you _must_ do it _ES5_ and _plain ES6_.
The following re-implementation of the `HeroComponent` reminds us that _any property metadata decorator_
can be expressed as component or directive metadata in both _TypeScript_ and _ES6-with-decorators_.
These particular _TypeScript_ and _ES6_ code snippets happen to be identical.
+makeTabs(`
cb-ts-to-js/ts/app/hero-host-meta.component.ts,
cb-ts-to-js/js-es6-decorators/app/hero-host-meta.component.es6
`,
'',
` TypeScript,
ES6 JavaScript with decorators
`)
a#view-child-decorators
.l-main-section
:marked
### View and Child Decorators
There are several property decorators for querying the descendants of
a component or directive.
Several _property_ decorators query a component's nested view and content components.
.l-sub-section
:marked
_View_ children are associated with element tags that appear _within_ the component's template.
_Content_ children are associated with elements that appear _between_ the component's element tags;
they are projected into an `<ng-content>` slot in the component's template.
:marked
The [`@ViewChild`](../api/core/index/ViewChild-decorator.html) and
[`@ViewChildren`](../api/core/index/ViewChildren-decorator.html) property decorators
allow a component to query instances of other components that are used in
its view.
In _ES5_/_ES6_ JavaScript you access a component's view children by adding a `queries` attribute to
the component metadata. It should be an object where:
* Each key is the name of a component property that will hold the view children
* Each value is an instance of either `ViewChild` or `ViewChildren`.
In _ES5_ and _ES6_, you access a component's view children by adding a `queries` property to the component metadata.
The `queries` property value is a hash map.
* each _key_ is the name of a component property that will hold the view child or children.
* each _value_ is a new instance of either `ViewChild` or `ViewChildren`.
+makeTabs(`
cb-ts-to-js/ts/app/heroes-queries.component.ts,
cb-ts-to-js/js-es6-decorators/app/heroes-queries.component.es6,
cb-ts-to-js/js-es6/app/heroes-queries.component.es6,
cb-ts-to-js/js/app/heroes-queries.component.js
`,`
view,
view,
view,
view
`,`
TypeScript,
cb-ts-to-js/ts/app/hero-queries.component.ts,
cb-ts-to-js/js-es6-decorators/app/hero-queries.component.es6,
cb-ts-to-js/js-es6/app/hero-queries.component.es6,
cb-ts-to-js/js/app/hero-queries.component.js
`,
'view, view, view, view',
` TypeScript,
ES6 JavaScript with decorators,
ES6 JavaScript,
ES5 JavaScript
ES5 JavaScript with DSL
`)
:marked
@ -560,22 +640,23 @@ a#host-query-metadata
[`@ViewChildren`](../api/core/index/ViewChildren-decorator.html).
+makeTabs(`
cb-ts-to-js/ts/app/heroes-queries.component.ts,
cb-ts-to-js/js-es6-decorators/app/heroes-queries.component.es6,
cb-ts-to-js/js-es6/app/heroes-queries.component.es6,
cb-ts-to-js/js/app/heroes-queries.component.js
`,`
content,
content,
content,
content
`,`
TypeScript,
cb-ts-to-js/ts/app/hero-queries.component.ts,
cb-ts-to-js/js-es6-decorators/app/hero-queries.component.es6,
cb-ts-to-js/js-es6/app/hero-queries.component.es6,
cb-ts-to-js/js/app/hero-queries.component.js
`,
'content, content, content, content',
` TypeScript,
ES6 JavaScript with decorators,
ES6 JavaScript,
ES5 JavaScript
ES5 JavaScript with DSL
`)
.alert.is-helpful
:marked
In _TypeScript_ and _ES6-with-decorators_ you can also use the `queries` metadata
instead of the `@ViewChild` and `@ContentChild` property decorators.
a#aot
.l-main-section
:marked