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

@ -9,7 +9,7 @@ describe('TypeScript to Javascript tests', function () {
}); });
it('should display the basic component example', 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 () { 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 () { it('should support component with inputs and outputs', function () {
let app = element(by.css('hero-io')); 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(); confirmComponent.element(by.buttonText('OK')).click();
expect(app.element(by.cssContainingText('span', 'OK clicked')).isPresent()).toBe(true); 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() { 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')); let h1 = app.element(by.css('h1'));
expect(app.getAttribute('class')).toBe('heading'); expect(app.getAttribute('class')).toBe('heading');
expect(app.getAttribute('title')).toBe('Tooltip content'); expect(app.getAttribute('title')).toContain('Tooltip');
h1.click(); h1.click();
expect(h1.getAttribute('class')).toBe('active'); expect(h1.getAttribute('class')).toBe('active');
@ -61,12 +61,12 @@ describe('TypeScript to Javascript tests', function () {
}); });
it('should support content and view queries', function() { it('should support content and view queries', function() {
let app = element(by.css('heroes-queries')); let app = element(by.css('hero-queries'));
let windstorm = app.element(by.css('a-hero:first-child')); 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('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) { 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() @Injectable()
export class DataService { export class DataService {
constructor() { constructor() { }
}
getHeroName() { getHeroName() {
return 'Windstorm'; return 'Windstorm';
} }

View File

@ -1,49 +1,7 @@
import { import { Component } from '@angular/core';
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
@Component({ @Component({
selector: 'hero-di-inject-additional', selector: 'hero-di-inject-additional',
template: `<hero-title title="Tour of Heroes"> template: `<hero-title title="Tour of Heroes"></hero-title>`
</hero-title>`
}) })
class AppComponent { } export class HeroComponent { }
@NgModule({
imports: [ BrowserModule ],
declarations: [
AppComponent,
TitleComponent
],
bootstrap: [ AppComponent ]
})
export class HeroesDIInjectAdditionalModule { }

View File

@ -1,22 +1,13 @@
import { Component, Inject, NgModule } from '@angular/core'; import { Component, Inject } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
// #docregion // #docregion
@Component({ @Component({
selector: 'hero-di-inject', selector: 'hero-di-inject',
template: `<h1>Hero: {{name}}</h1>` template: `<h1>Hero: {{name}}</h1>`
}) })
class HeroComponent { export class HeroComponent {
constructor(@Inject('heroName') name) { constructor(@Inject('heroName') name) {
this.name = name; this.name = name;
} }
} }
// #enddocregion // #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 { Component } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { DataService } from './data.service'; import { DataService } from './data.service';
// #docregion // #docregion
@ -8,19 +6,10 @@ import { DataService } from './data.service';
selector: 'hero-di', selector: 'hero-di',
template: `<h1>Hero: {{name}}</h1>` template: `<h1>Hero: {{name}}</h1>`
}) })
export class HeroComponent {
class HeroComponent { name = '';
name;
constructor(dataService: DataService) { constructor(dataService: DataService) {
this.name = dataService.getHeroName(); this.name = dataService.getHeroName();
} }
} }
// #enddocregion // #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 { import { Component } from '@angular/core';
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
@Component({ @Component({
selector: 'hero-io', selector: 'hero-io',
template: ` template: `
<my-confirm [okMsg]="'OK'" <app-confirm [okMsg]="'OK'"
[cancelMsg]="'Cancel'" [cancelMsg]="'Cancel'"
(ok)="onOk()" (ok)="onOk()"
(cancel)="onCancel()"> (cancel)="onCancel()">
</my-confirm> </app-confirm>
<span *ngIf="okClicked">OK clicked</span> <span *ngIf="okClicked">OK clicked</span>
<span *ngIf="cancelClicked">Cancel clicked</span> <span *ngIf="cancelClicked">Cancel clicked</span>
` `
}) })
class AppComponent { export class HeroIOComponent {
okClicked; okClicked = false;
cancelClicked; cancelClicked = false;
onOk() { onOk() {
this.okClicked = true; this.okClicked = true;
} }
onCancel() { onCancel() {
this.cancelClicked = true; this.cancelClicked = true;
} }
} }
@NgModule({
imports: [ BrowserModule ],
declarations: [
AppComponent,
ConfirmComponent
],
bootstrap: [ AppComponent ]
})
export class HeroesIOModule { }

View File

@ -1,27 +1,14 @@
// #docplaster
// #docregion // #docregion
import { Component, OnInit } from '@angular/core'; import { Component } from '@angular/core';
// #enddocregion
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@Component({ @Component({
selector: 'hero-lifecycle', selector: 'hero-lifecycle',
template: `<h1>Hero: {{name}}</h1>` template: `<h1>Hero: {{name}}</h1>`
}) })
// #docregion export class HeroComponent {
class HeroComponent{ name = '';
name;
ngOnInit() { 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 // #docregion metadata
import { Component } from '@angular/core'; import { Component } from '@angular/core';
@ -6,24 +5,10 @@ import { Component } from '@angular/core';
selector: 'hero-view', selector: 'hero-view',
template: '<h1>{{title}}: {{getName()}}</h1>' template: '<h1>{{title}}: {{getName()}}</h1>'
}) })
// #docregion appexport // #docregion appexport, class
// #docregion class
export class HeroComponent { export class HeroComponent {
title = 'Hero Detail'; title = 'Hero Detail';
getName() {return 'Windstorm'; } getName() {return 'Windstorm'; }
} }
// #enddocregion class // #enddocregion appexport, class
// #enddocregion appexport
// #enddocregion metadata // #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 { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { import { AppModule } from './app.module';
LocationStrategy,
HashLocationStrategy
} from '@angular/common';
// #enddocregion ng2import
// #docregion appimport platformBrowserDynamic().bootstrapModule(AppModule);
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);

View File

@ -5,6 +5,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" href="styles.css">
<title>TypeScript to JavaScript</title>
<!-- Polyfill(s) for older browsers --> <!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/core-js/client/shim.min.js"></script>
@ -20,32 +21,7 @@
</head> </head>
<body> <body>
<a id="toc"></a> <my-app>Loading...</my-app>
<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>
</body> </body>
</html> </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 { import { Component } from '@angular/core';
Attribute,
Component,
Inject,
Optional,
NgModule
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
// #docregion export class HeroComponent { }
class TitleComponent {
constructor(titlePrefix, title) {
this.titlePrefix = titlePrefix;
this.title = title;
this.msg = '';
}
ok() { HeroComponent.annotations = [
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 = [
new Component({ new Component({
selector: 'hero-di-inject-additional', selector: 'hero-di-inject-additional',
template: `<hero-title title="Tour of Heroes"> template: `<hero-title title="Tour of Heroes"></hero-title>`
</hero-title>`
})
];
export class HeroesDIInjectAdditionalModule { }
HeroesDIInjectAdditionalModule.annotations = [
new NgModule({
imports: [ BrowserModule ],
declarations: [
AppComponent,
TitleComponent
],
bootstrap: [ AppComponent ]
}) })
]; ];

View File

@ -1,8 +1,7 @@
import { Component, Inject, NgModule } from '@angular/core'; import { Component, Inject } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
// #docregion // #docregion
class HeroComponent { export class HeroComponent {
constructor(name) { constructor(name) {
this.name = name; this.name = name;
} }
@ -19,14 +18,3 @@ HeroComponent.parameters = [
[new Inject('heroName')] [new Inject('heroName')]
]; ];
// #enddocregion // #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 { Component } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { DataService } from './data.service'; import { DataService } from './data.service';
// #docregion // #docregion
class HeroComponent { export class HeroComponent {
constructor(dataService) { constructor(dataService) {
this.name = dataService.getHeroName(); this.name = dataService.getHeroName();
} }
@ -22,14 +20,3 @@ HeroComponent.parameters = [
]; ];
// #enddocregion // #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 { import { Component } from '@angular/core';
Component,
EventEmitter,
Input,
Output,
NgModule
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
// #docregion export class HeroIOComponent {
class ConfirmComponent {
constructor() { constructor() {
this.ok = new EventEmitter(); this.okClicked = false;
this.notOk = new EventEmitter(); 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() { onOk() {
this.okClicked = true; this.okClicked = true;
} }
onCancel() { onCancel() {
this.cancelClicked = true; this.cancelClicked = true;
} }
} }
AppComponent.annotations = [ HeroIOComponent.annotations = [
new Component({ new Component({
selector: 'hero-io', selector: 'hero-io',
template: ` template: `
<my-confirm [okMsg]="'OK'" <app-confirm [okMsg]="'OK'"
[cancelMsg]="'Cancel'" [cancelMsg]="'Cancel'"
(ok)="onOk()" (ok)="onOk()"
(cancel)="onCancel()"> (cancel)="onCancel()">
</my-confirm> </app-confirm>
<span *ngIf="okClicked">OK clicked</span> <span *ngIf="okClicked">OK clicked</span>
<span *ngIf="cancelClicked">Cancel 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 // #docregion
import { Component } from '@angular/core'; import { Component } from '@angular/core';
// #enddocregion export class HeroComponent {
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
// #docregion
class HeroComponent {
ngOnInit() { ngOnInit() {
this.name = 'Windstorm'; // todo: fetch from server async
setTimeout(() => this.name = 'Windstorm', 0);
} }
} }
// #enddocregion
HeroComponent.annotations = [ HeroComponent.annotations = [
new Component({ new Component({
@ -19,13 +13,3 @@ HeroComponent.annotations = [
template: `<h1>Hero: {{name}}</h1>` 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> <h1>{{titlePrefix}} {{title}}</h1>
<button (click)="ok()">OK</button> <button (click)="ok()">OK</button>
<p>{{ msg }}</p> <p>{{ msg }}</p>

View File

@ -2,16 +2,14 @@
// #docregion metadata // #docregion metadata
import { Component } from '@angular/core'; import { Component } from '@angular/core';
// #docregion class // #docregion appexport, class
// #docregion appexport
export class HeroComponent { export class HeroComponent {
constructor() { constructor() {
this.title = 'Hero Detail'; this.title = 'Hero Detail';
} }
getName() {return 'Windstorm'; } getName() {return 'Windstorm'; }
} }
// #enddocregion appexport // #enddocregion appexport, class
// #enddocregion class
HeroComponent.annotations = [ HeroComponent.annotations = [
new Component({ new Component({
@ -20,18 +18,3 @@ HeroComponent.annotations = [
}) })
]; ];
// #enddocregion metadata // #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 { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { import { AppModule } from './app.module';
LocationStrategy,
HashLocationStrategy
} from '@angular/common';
// #enddocregion ng2import
// #docregion appimport platformBrowserDynamic().bootstrapModule(AppModule);
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);

View File

@ -5,6 +5,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" href="styles.css">
<title>TypeScript to JavaScript</title>
<!-- Polyfill(s) for older browsers --> <!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/core-js/client/shim.min.js"></script>
@ -20,33 +21,7 @@
</head> </head>
<body> <body>
<a id="toc"></a> <my-app>Loading...</my-app>
<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>
</body> </body>
</html> </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(app) {
function DataService() { app.DataService = DataService;
} function DataService() { }
DataService.annotations = [
new ng.core.Injectable()
];
DataService.prototype.getHeroName = function() { DataService.prototype.getHeroName = function() {
return 'Windstorm'; return 'Windstorm';
}; };
app.DataService = DataService;
})(window.app = window.app || {}); })(window.app = window.app || {});

View File

@ -1,47 +1,26 @@
(function(app) { (function(app) {
// #docregion app.HeroDIInjectAdditionalComponent = HeroDIInjectAdditionalComponent;
// #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
var AppComponent = ng.core.Component({ HeroDIInjectAdditionalComponent.annotations = [
new ng.core.Component({
selector: 'hero-di-inject-additional', selector: 'hero-di-inject-additional',
template: '<hero-title title="Tour of Heroes">' + template: '<hero-title title="Tour of Heroes"></hero-title>'
'</hero-title>'
}).Class({
constructor: function() { }
});
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 || {}); })(window.app = window.app || {});

View File

@ -1,58 +1,41 @@
(function(app) { (function(app) {
// #docregion parameters // #docregion
function HeroComponent(name) { app.HeroDIInjectComponent = HeroDIInjectComponent;
this.name = name;
} HeroDIInjectComponent.annotations = [
HeroComponent.parameters = [
'heroName'
];
HeroComponent.annotations = [
new ng.core.Component({ new ng.core.Component({
selector: 'hero-di-inject', selector: 'hero-di-inject',
template: '<h1>Hero: {{name}}</h1>' template: '<h1>Hero: {{name}}</h1>'
}) })
]; ];
// #enddocregion parameters
app.HeroesDIInjectModule = HeroDIInjectComponent.parameters = [ 'heroName' ];
ng.core.NgModule({
imports: [ ng.platformBrowser.BrowserModule ], function HeroDIInjectComponent(name) {
providers: [ { provide: 'heroName', useValue: 'Windstorm' } ], this.name = name;
declarations: [ HeroComponent ], }
bootstrap: [ HeroComponent ] // #enddocregion
})
.Class({
constructor: function() {}
});
})(window.app = window.app || {}); })(window.app = window.app || {});
/////// DSL version ////////
(function(app) { (function(app) {
// #docregion ctor
var HeroComponent = ng.core.Component({ // #docregion dsl
selector: 'hero-di-inline2', app.HeroDIInjectDslComponent = ng.core.Component({
selector: 'hero-di-inject-dsl',
template: '<h1>Hero: {{name}}</h1>' template: '<h1>Hero: {{name}}</h1>'
}) })
.Class({ .Class({
constructor: [ constructor: [
new ng.core.Inject('heroName'), new ng.core.Inject('heroName'),
function(name) { function HeroDIInjectDslComponent(name) {
this.name = name; this.name = name;
} }
] ]
}); });
// #enddocregion ctor // #enddocregion dsl
app.HeroesDIInjectModule2 =
ng.core.NgModule({
imports: [ ng.platformBrowser.BrowserModule ],
providers: [ { provide: 'heroName', useValue: 'Bombasto' } ],
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ]
})
.Class({
constructor: function() {}
});
})(window.app = window.app || {}); })(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) { (function(app) {
// #docregion // #docregion
app.HeroDIComponent = HeroComponent; app.HeroDIComponent = HeroDIComponent;
function HeroComponent(dataService) { HeroDIComponent.annotations = [
this.name = dataService.getHeroName();
}
HeroComponent.parameters = [
app.DataService
];
HeroComponent.annotations = [
new ng.core.Component({ new ng.core.Component({
selector: 'hero-di', selector: 'hero-di',
template: '<h1>Hero: {{name}}</h1>' template: '<h1>Hero: {{name}}</h1>'
}) })
]; ];
HeroDIComponent.parameters = [ app.DataService ];
function HeroDIComponent(dataService) {
this.name = dataService.getHeroName();
}
// #enddocregion // #enddocregion
app.HeroesDIModule =
ng.core.NgModule({ })(window.app = window.app || {});
imports: [ ng.platformBrowser.BrowserModule ],
providers: [ app.DataService ], ////// DSL Version /////
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ] (function(app) {
})
.Class({ // #docregion dsl
constructor: function() {} 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 || {}); })(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) { (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() { app.HeroIOComponent = HeroComponent;
}
AppComponent.annotations = [ HeroComponent.annotations = [
new ng.core.Component({ new ng.core.Component({
selector: 'hero-io', selector: 'hero-io',
template: '<my-confirm [okMsg]="\'OK\'"' + templateUrl: 'app/hero-io.component.html'
'[cancelMsg]="\'Cancel\'"' +
'(ok)="onOk()"' +
'(cancel)="onCancel()">' +
'</my-confirm>' +
'<span *ngIf="okClicked">OK clicked</span>' +
'<span *ngIf="cancelClicked">Cancel clicked</span>'
}) })
]; ];
AppComponent.prototype.onOk = function() {
function HeroComponent() { }
HeroComponent.prototype.onOk = function() {
this.okClicked = true; this.okClicked = true;
} }
AppComponent.prototype.onCancel = function() {
HeroComponent.prototype.onCancel = function() {
this.cancelClicked = true; this.cancelClicked = true;
} }
app.HeroesIOModule = })(window.app = window.app || {});
ng.core.NgModule({
imports: [ ng.platformBrowser.BrowserModule ], ///// DSL Version ////
declarations: [
AppComponent, (function(app) {
ConfirmComponent
], app.HeroIODslComponent = ng.core.Component({
bootstrap: [ AppComponent ] selector: 'hero-io-dsl',
templateUrl: 'app/hero-io-dsl.component.html'
}) })
.Class({ .Class({
constructor: function() {} constructor: function HeroIODslComponent() { },
onOk: function() {
this.okClicked = true;
},
onCancel: function() {
this.cancelClicked = true;
}
}); });
})(window.app = window.app || {}); })(window.app = window.app || {});

View File

@ -1,28 +1,42 @@
// #docplaster // #docplaster
(function(app) { (function(app) {
// #docregion // #docregion
function HeroComponent() {} app.HeroLifecycleComponent = HeroComponent;
// #enddocregion
HeroComponent.annotations = [ HeroComponent.annotations = [
new ng.core.Component({ new ng.core.Component({
selector: 'hero-lifecycle', selector: 'hero-lifecycle',
template: '<h1>Hero: {{name}}</h1>' template: '<h1>Hero: {{name}}</h1>'
}) })
]; ];
// #docregion
function HeroComponent() { }
HeroComponent.prototype.ngOnInit = function() { HeroComponent.prototype.ngOnInit = function() {
this.name = 'Windstorm'; // todo: fetch from server async
setTimeout(() => this.name = 'Windstorm', 0);
}; };
// #enddocregion // #enddocregion
app.HeroesLifecycleModule = })(window.app = window.app || {});
ng.core.NgModule({
imports: [ ng.platformBrowser.BrowserModule ], /////// DSL version ////
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ] (function(app) {
// #docregion dsl
app.HeroLifecycleDslComponent = ng.core.Component({
selector: 'hero-lifecycle-dsl',
template: '<h1>Hero: {{name}}</h1>'
}) })
.Class({ .Class({
constructor: function() {} constructor: function HeroLifecycleDslComponent() { },
ngOnInit: function() {
// todo: fetch from server async
setTimeout(() => this.name = 'Windstorm', 0);
}
}); });
// #enddocregion dsl
})(window.app = window.app || {}); })(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> <h1>{{titlePrefix}} {{title}}</h1>
<button (click)="ok()">OK</button> <button (click)="ok()">OK</button>
<p>{{ msg }}</p> <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 // #docplaster
// #docregion appexport
(function(app) { (function(app) {
// #enddocregion appexport
// #docregion metadata // #docregion
// #docregion appexport // #docregion appexport
// #docregion constructorproto // #docregion metadata
function HeroComponent() { app.HeroComponent = HeroComponent; // "export"
this.title = "Hero Detail";
}
HeroComponent.prototype.getName = function() { return 'Windstorm'; };
// #enddocregion constructorproto
// #enddocregion appexport
HeroComponent.annotations = [ HeroComponent.annotations = [
new ng.core.Component({ new ng.core.Component({
selector: 'hero-view', selector: 'hero-view',
template: '<h1>{{title}}: {{getName()}}</h1>' template: '<h1>{{title}}: {{getName()}}</h1>'
}) })
]; ];
// #docregion constructorproto
function HeroComponent() {
this.title = "Hero Detail";
}
HeroComponent.prototype.getName = function() { return 'Windstorm'; };
// #enddocregion constructorproto
// #enddocregion metadata // #enddocregion metadata
// #enddocregion appexport
app.HeroesModule = // #enddocregion
ng.core.NgModule({
imports: [ ng.platformBrowser.BrowserModule ], })(window.app = window.app || {});
declarations: [ HeroComponent ],
bootstrap: [ HeroComponent ] //////////// DSL version ///////////
})
.Class({ (function(app) {
constructor: function() {}
}); // #docregion dsl
app.HeroDslComponent = ng.core.Component({
// #docregion appexport selector: 'hero-view-dsl',
app.HeroComponent = HeroComponent; template: '<h1>{{title}}: {{getName()}}</h1>',
})
.Class({
constructor: function HeroDslComponent() {
this.title = "Hero Detail";
},
getName: function() { return 'Windstorm'; }
});
// #enddocregion dsl
})(window.app = window.app || {}); })(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) { (function(app) {
// #enddocregion appimport
// #docregion ng2import
var platformBrowserDynamic = ng.platformBrowserDynamic.platformBrowserDynamic; var platformBrowserDynamic = ng.platformBrowserDynamic.platformBrowserDynamic;
var LocationStrategy = ng.common.LocationStrategy;
var HashLocationStrategy = ng.common.HashLocationStrategy;
// #enddocregion ng2import
// #docregion appimport
var HeroComponent = app.HeroComponent;
// #enddocregion appimport
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
platformBrowserDynamic().bootstrapModule(app.HeroesModule); platformBrowserDynamic().bootstrapModule(app.AppModule);
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 || {}); })(window.app = window.app || {});
// #enddocregion appimport

View File

@ -4,12 +4,14 @@
<base href="/"> <base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css"> <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/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script> <script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.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/rxjs/bundles/Rx.js"></script>
<script src="node_modules/@angular/core/bundles/core.umd.js"></script> <script src="node_modules/@angular/core/bundles/core.umd.js"></script>
<script src="node_modules/@angular/common/bundles/common.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/bundles/platform-browser.umd.js"></script>
<script src="node_modules/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.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/data.service.js"></script>
<script src="app/hero.component.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-io.component.js"></script>
<script src="app/hero-di.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.component.js"></script>
<script src="app/hero-di-inject-additional.component.js"></script> <script src="app/hero-di-inject-additional.component.js"></script>
<script src="app/heroes-bindings.component.js"></script> <script src="app/hero-host.component.js"></script>
<script src="app/heroes-queries.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> <script src="app/main.js"></script>
</head> </head>
<body> <body>
<a id="toc"></a> <my-app>Loading...</my-app>
<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>
</body> </body>
</html> </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() @Injectable()
export class DataService { export class DataService {
constructor() { constructor() { }
}
getHeroName() { getHeroName() {
return 'Windstorm'; return 'Windstorm';
} }

View File

@ -1,46 +1,7 @@
import { import { Component } from '@angular/core';
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
@Component({ @Component({
selector: 'hero-di-inject-additional', selector: 'hero-di-inject-additional',
template: `<hero-title title="Tour of Heroes"> template: `<hero-title title="Tour of Heroes"></hero-title>`
</hero-title>`
}) })
class AppComponent { } export class HeroComponent { }
@NgModule({
imports: [ BrowserModule ],
declarations: [
AppComponent,
TitleComponent
],
bootstrap: [ AppComponent ]
})
export class HeroesDIInjectAdditionalModule { }

View File

@ -1,20 +1,11 @@
import { Component, Inject, NgModule } from '@angular/core'; import { Component, Inject } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
// #docregion // #docregion
@Component({ @Component({
selector: 'hero-di-inject', selector: 'hero-di-inject',
template: `<h1>Hero: {{name}}</h1>` template: `<h1>Hero: {{name}}</h1>`
}) })
class HeroComponent { export class HeroComponent {
constructor(@Inject('heroName') private name: string) { } constructor(@Inject('heroName') private name: string) { }
} }
// #enddocregion // #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 { Component } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { DataService } from './data.service'; import { DataService } from './data.service';
// #docregion // #docregion
@ -8,19 +6,10 @@ import { DataService } from './data.service';
selector: 'hero-di', selector: 'hero-di',
template: `<h1>Hero: {{name}}</h1>` template: `<h1>Hero: {{name}}</h1>`
}) })
export class HeroComponent {
class HeroComponent { name = '';
name: string;
constructor(dataService: DataService) { constructor(dataService: DataService) {
this.name = dataService.getHeroName(); this.name = dataService.getHeroName();
} }
} }
// #enddocregion // #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 { import { Component } from '@angular/core';
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
@Component({ @Component({
selector: 'hero-io', selector: 'hero-io',
template: ` template: `
<my-confirm [okMsg]="'OK'" <app-confirm [okMsg]="'OK'"
[cancelMsg]="'Cancel'" [cancelMsg]="'Cancel'"
(ok)="onOk()" (ok)="onOk()"
(cancel)="onCancel()"> (cancel)="onCancel()">
</my-confirm> </app-confirm>
<span *ngIf="okClicked">OK clicked</span> <span *ngIf="okClicked">OK clicked</span>
<span *ngIf="cancelClicked">Cancel clicked</span> <span *ngIf="cancelClicked">Cancel clicked</span>
` `
}) })
class AppComponent { export class HeroIOComponent {
okClicked: boolean; okClicked = false;
cancelClicked: boolean; cancelClicked = false;
onOk() { onOk() {
this.okClicked = true; this.okClicked = true;
} }
onCancel() { onCancel() {
this.cancelClicked = true; this.cancelClicked = true;
} }
} }
@NgModule({
imports: [ BrowserModule ],
declarations: [
AppComponent,
ConfirmComponent
],
bootstrap: [ AppComponent ]
})
export class HeroesIOModule { }

View File

@ -1,27 +1,14 @@
// #docplaster
// #docregion // #docregion
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
// #enddocregion
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@Component({ @Component({
selector: 'hero-lifecycle', selector: 'hero-lifecycle',
template: `<h1>Hero: {{name}}</h1>` template: `<h1>Hero: {{name}}</h1>`
}) })
// #docregion export class HeroComponent implements OnInit {
class HeroComponent implements OnInit {
name: string; name: string;
ngOnInit() { 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> <h1>{{titlePrefix}} {{title}}</h1>
<button (click)="ok()">OK</button> <button (click)="ok()">OK</button>
<p>{{ msg }}</p> <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 // #docregion metadata
import { Component } from '@angular/core'; import { Component } from '@angular/core';
@ -6,24 +5,10 @@ import { Component } from '@angular/core';
selector: 'hero-view', selector: 'hero-view',
template: '<h1>{{title}}: {{getName()}}</h1>' template: '<h1>{{title}}: {{getName()}}</h1>'
}) })
// #docregion appexport // #docregion appexport, class
// #docregion class
export class HeroComponent { export class HeroComponent {
title = 'Hero Detail'; title = 'Hero Detail';
getName() {return 'Windstorm'; } getName() {return 'Windstorm'; }
} }
// #enddocregion class // #enddocregion appexport, class
// #enddocregion appexport
// #enddocregion metadata // #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 { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { import { AppModule } from './app.module';
LocationStrategy,
HashLocationStrategy
} from '@angular/common';
// #enddocregion ng2import
// #docregion appimport platformBrowserDynamic().bootstrapModule(AppModule);
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);

View File

@ -5,6 +5,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" href="styles.css">
<title>TypeScript to JavaScript</title>
<!-- Polyfills for older browsers --> <!-- Polyfills for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/core-js/client/shim.min.js"></script>
@ -20,32 +21,7 @@
</head> </head>
<body> <body>
<a id="toc"></a> <my-app>Loading...</my-app>
<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>
</body> </body>
</html> </html>

View File

@ -15,19 +15,16 @@ a#toc
:marked :marked
## Table of contents ## Table of contents
[_TypeScript_ to _ES6_ to _ES5_](#from-ts) [_TypeScript_ to _ES6_ to _ES5_](#from-ts)<br>
[Modularity: imports and exports](#modularity)<br>
[Modularity: imports and exports](#modularity) [Classes and Class Metadata](#class-metadata)<br>
[_ES5_ DSL](#dsl)<br>
[Classes and Class Metadata](#class-metadata) [Interfaces](#interfaces)<br>
[Input and Output Metadata](#io-decorators)<br>
[Input and Output Metadata](#property-metadata) [Dependency Injection](#dependency-injection)<br>
[Host Binding](#host-binding)<br>
[Dependency Injection](#dependency-injection) [View and Child Decorators](#view-child-decorators)<br>
[AoT compilation in _TypeScript_ Only](#aot)<br>
[Host and Query Metadata](#host-query-metadata)
[AoT compilation in _TypeScript_ Only](#aot)
**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> **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.** code shown in this cookbook.**
@ -38,7 +35,7 @@ a#from-ts
## _TypeScript_ to _ES6_ to _ES5_ ## _TypeScript_ to _ES6_ to _ES5_
_TypeScript_ _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. &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. 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_ * _ES6-without-decorators_ to _ES5_
When translating from _TypeScript_ to _ES6-with-decorators_, remove 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`. such as `public` and `private`.
Remove most of the Remove most of the
[type annotations](https://www._TypeScript_lang.org/docs/handbook/basic-types.html), [type declarations](https://www.typescriptlang.org/docs/handbook/basic-types.html),
such as `string` and `boolean` such as `:string` and `:boolean`
but **keep type annotations used for dependency injection**. but **keep the constructor parameter types which are used for dependency injection**.
From _ES6-with-decorators_ to _plain ES6_, remove all From _ES6-with-decorators_ to _plain ES6_, remove all
[decorators](https://www._TypeScript_lang.org/docs/handbook/decorators.html) [decorators](https://www.typescriptlang.org/docs/handbook/decorators.html)
and the remaining type annotations. and the remaining types.
You must declare properties in the class constructor (`this.title = '...'`) rather than in the body of the class. 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` 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) In _ES5_, you access the Angular entities of the [the Angular packages](../glossary.html#!#scoped-package)
through the global `ng` object. 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(` +makeTabs(`
cb-ts-to-js/ts/app/main.ts, cb-ts-to-js/ts/app/app.module.ts,
cb-ts-to-js/js-es6-decorators/app/main.es6, cb-ts-to-js/js-es6-decorators/app/app.module.es6,
cb-ts-to-js/js-es6/app/main.es6, cb-ts-to-js/js-es6/app/app.module.es6,
cb-ts-to-js/js/app/main.js cb-ts-to-js/js/app/app.module.js
`,` `,
ng2import, 'ng2import,ng2import,ng2import,ng2import',
ng2import, ` TypeScript,
ng2import,
ng2import
`,`
TypeScript,
ES6 JavaScript with decorators, ES6 JavaScript with decorators,
ES6 JavaScript, ES6 JavaScript,
ES5 JavaScript ES5 JavaScript
`) `)(format='.')
:marked :marked
### Exporting Application Code ### Exporting Application Code
@ -118,9 +111,9 @@ a#modularity
Add one application namespace object such as `app` to the global `document`. 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`. 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 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) [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. 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-decorators/app/hero.component.es6,
cb-ts-to-js/js-es6/app/hero.component.es6, cb-ts-to-js/js-es6/app/hero.component.es6,
cb-ts-to-js/js/app/hero.component.js cb-ts-to-js/js/app/hero.component.js
`,` `,
appexport, 'appexport,appexport,appexport,appexport',
appexport, ` TypeScript,
appexport,
appexport
`,`
TypeScript,
ES6 JavaScript with decorators, ES6 JavaScript with decorators,
ES6 JavaScript, ES6 JavaScript,
ES5 JavaScript ES5 JavaScript
@ -151,17 +140,13 @@ a#modularity
In _ES5_ you use the shared namespace object to access "exported" entities from other files. In _ES5_ you use the shared namespace object to access "exported" entities from other files.
+makeTabs(` +makeTabs(`
cb-ts-to-js/ts/app/main.ts, cb-ts-to-js/ts/app/app.module.ts,
cb-ts-to-js/js-es6-decorators/app/main.es6, cb-ts-to-js/js-es6-decorators/app/app.module.es6,
cb-ts-to-js/js-es6/app/main.es6, cb-ts-to-js/js-es6/app/app.module.es6,
cb-ts-to-js/js/app/main.js cb-ts-to-js/js/app/app.module.js
`,` `,
appimport, 'appimport,appimport,appimport,appimport',
appimport, ` TypeScript,
appimport,
appimport
`,`
TypeScript,
ES6 JavaScript with decorators, ES6 JavaScript with decorators,
ES6 JavaScript, ES6 JavaScript,
ES5 JavaScript ES5 JavaScript
@ -183,6 +168,20 @@ a#class-metadata
### Classes ### Classes
Most Angular _TypeScript_ and _ES6_ code is written as 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. In _ES6-without-decorators_, properties of classes must be assigned inside the constructor.
_ES5_ JavaScript has no classes. _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-decorators/app/hero.component.es6,
cb-ts-to-js/js-es6/app/hero.component.es6, cb-ts-to-js/js-es6/app/hero.component.es6,
cb-ts-to-js/js/app/hero.component.js cb-ts-to-js/js/app/hero.component.js
`,` `,
class, 'class,class,class,constructorproto',
class, ` TypeScript,
class,
constructorproto
`,`
TypeScript,
ES6 JavaScript with decorators, ES6 JavaScript with decorators,
ES6 JavaScript, ES6 JavaScript,
ES5 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-decorators/app/hero.component.es6,
cb-ts-to-js/js-es6/app/hero.component.es6, cb-ts-to-js/js-es6/app/hero.component.es6,
cb-ts-to-js/js/app/hero.component.js cb-ts-to-js/js/app/hero.component.js
`,` `,
metadata, 'metadata,metadata,metadata,metadata',
metadata, ` TypeScript,
metadata,
metadata
`,`
TypeScript,
ES6 JavaScript with decorators, ES6 JavaScript with decorators,
ES6 JavaScript, ES6 JavaScript,
ES5 JavaScript ES5 JavaScript
@ -242,62 +233,95 @@ a#class-metadata
***External Template file*** ***External Template file***
A large component template is often kept in a separate 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 :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(` +makeTabs(`
cb-ts-to-js/ts/app/hero-di-inject-additional.component.ts, cb-ts-to-js/ts/app/hero-title.component.ts,
cb-ts-to-js/js-es6-decorators/app/hero-di-inject-additional.component.es6, cb-ts-to-js/js-es6-decorators/app/hero-title.component.es6,
cb-ts-to-js/js-es6/app/hero-di-inject-additional.component.es6, cb-ts-to-js/js-es6/app/hero-title.component.es6,
cb-ts-to-js/js/app/hero-di-inject-additional.component.js`, cb-ts-to-js/js/app/hero-title.component.js`,
'metadata, metadata, metadata, metadata', 'templateUrl, templateUrl, templateUrl, templateUrl',
`TypeScript, `TypeScript,
ES6 JavaScript with decorators, ES6 JavaScript with decorators,
ES6 JavaScript, ES6 JavaScript,
ES5 JavaScript`)(format='.') ES5 JavaScript
`)(format='.')
:marked :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 All three metadata configurations specify the `moduleId` property
so that Angular can calculate the proper module address. 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 _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 The `templateUrl` for the _ES5_ code must specify the _path from the project root_ and
omits the irrelevant `moduleId` property. 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 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, 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_. 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_).
Pass the same metadata object to `ng.core.Component` as you did before.
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. 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(` +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 cb-ts-to-js/js/app/hero.component.js
`,` `,
component, 'dsl,',
metadata `
`,` ES5 JavaScript with DSL,
ES5 JavaScript with Class API,
ES5 JavaScript ES5 JavaScript
`) `)
.callout.is-helpful
header Name the constructor
:marked :marked
There are similar APIs for other decorated classes. 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
### 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`: You can define a directive with `ng.core.Directive`:
code-example. code-example.
var MyDirective = ng.core.Directive({ app.MyDirective = ng.core.Directive({
selector: '[myDirective]' selector: '[myDirective]'
}).Class({ }).Class({
... ...
@ -305,18 +329,20 @@ code-example.
:marked :marked
and a pipe with `ng.core.Pipe`: and a pipe with `ng.core.Pipe`:
code-example. code-example.
var MyPipe = ng.core.Pipe({ app.MyPipe = ng.core.Pipe({
name: 'myPipe' name: 'myPipe'
}).Class({ }).Class({
... ...
}); });
a#interfaces
.l-main-section
:marked :marked
### Interfaces ## Interfaces
A _TypeScript_ interface helps ensure that a class implements the interface's members correctly. A _TypeScript_ interface helps ensure that a class implements the interface's members correctly.
We strongly recommend Angular interfaces where appropriate. 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. should implement the `OnInit` interface.
_TypeScript_ interfaces exist for developer convenience and are not used by Angular at runtime. _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/ts/app/hero-lifecycle.component.ts,
cb-ts-to-js/js-es6-decorators/app/hero-lifecycle.component.es6, 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-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 cb-ts-to-js/js/app/hero-lifecycle.component.js
`,` `,
`,` ',,,,dsl',
TypeScript, ` TypeScript,
ES6 JavaScript with decorators, ES6 JavaScript with decorators,
ES6 JavaScript, ES6 JavaScript,
ES5 JavaScript ES5 JavaScript,
ES5 JavaScript with DSL
`) `)
a#property-metadata a#io-decorators
.l-main-section .l-main-section
:marked :marked
## Input and Output Metadata ## Input and Output Metadata
@ -357,16 +385,18 @@ a#property-metadata
combined in the metadata `inputs` and `outputs` _arrays_. combined in the metadata `inputs` and `outputs` _arrays_.
+makeTabs(` +makeTabs(`
cb-ts-to-js/ts/app/hero-io.component.ts, cb-ts-to-js/ts/app/confirm.component.ts,
cb-ts-to-js/js-es6-decorators/app/hero-io.component.es6, cb-ts-to-js/js-es6-decorators/app/confirm.component.es6,
cb-ts-to-js/js-es6/app/hero-io.component.es6, cb-ts-to-js/js-es6/app/confirm.component.es6,
cb-ts-to-js/js/app/hero-io.component.js cb-ts-to-js/js/app/confirm.component.js,
`,` cb-ts-to-js/js/app/confirm.component.js
`,` `,
TypeScript, ',,,,dsl',
` TypeScript,
ES6 JavaScript with decorators, ES6 JavaScript with decorators,
ES6 JavaScript, ES6 JavaScript,
ES5 JavaScript ES5 JavaScript,
ES5 JavaScript with DSL
`) `)
:marked :marked
In the previous example, one of the public-facing binding names (`cancelMsg`) 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_, In _TypeScript_ and _ES6-with-decorators_,
you specify the special binding name in the argument to the property decorator. 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. In _ES5_ and _plain ES6_ code, convey this pairing with the `propertyName: bindingName` syntax in the class metadata.
.l-main-section .l-main-section
:marked :marked
## Dependency Injection ## 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. ### Injection by Class Type
_ES6-with-decorators_ can also make use of type information.
Since no type information is available in _ES5_/_ES6_ JavaScript, you must identify "injectables" in The easiest and most popular technique in _TypeScript_ and _ES6-with-decorators_ is to set the constructor parameter type
some other way. to the class associated with the service to inject.
Attach a `parameters` array to the constructor function. The _TypeScript_ transpiler writes parameter type information into the generated JavaScript.
Each array item is the dependency injection token that identifies the thing to be injected. Angular reads that information at runtime and locates the corresponding service in the appropriate _Injector_..
Often the token is the constructor function for the class-like dependency. The _ES6-with-decorators_ transpiler does essentially the same thing using the same parameter-typing syntax.
In _ES6_ the decorators need to be inside a nested array. _ES5_ and _plain ES6_ lack types so you must identify "injectables" by attaching a **`parameters`** array to the constructor function.
When writing in the _ES5_ class convenience API, you can supply the parameter tokens by wrapping Each item in the array specifies the service's injection token.
the constructor in an array.
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(` +makeTabs(`
cb-ts-to-js/ts/app/hero-di.component.ts, 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-decorators/app/hero-di.component.es6,
cb-ts-to-js/js-es6/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.component.js,
cb-ts-to-js/js/app/hero-di-inline.component.js cb-ts-to-js/js/app/hero-di.component.js
`,` `,
`,` ',,,,dsl',
TypeScript, ` TypeScript,
ES6 JavaScript with decorators, ES6 JavaScript with decorators,
ES6 JavaScript, ES6 JavaScript,
ES5 JavaScript, ES5 JavaScript,
ES5 JavaScript with Class API ES5 JavaScript with DSL
`) `)
:marked :marked
### Injection with the @Inject decorator ### Injection with the @Inject decorator
When the thing being injected doesn't correspond directly to a type, you use the Sometimes the dependency injection token isn't a class or constructor function.
`@Inject()` decorator to supply the injection token.
In this example, you are injecting a string identified by the "heroName" token.
In _ES5_/_ES6_ JavaScript you add the token string to the injection parameters array. In _TypeScript_ and _ES6-with-decorators_, you precede the class constructor parameter
Alternatively, when using the _ES5_ convenience class API you can create a token with the by calling the `@Inject()` decorator with the injection token.
`Inject` method and add that to the constructor array in the annotations. In the following example, the token is the string `'heroName'`.
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(` +makeTabs(`
cb-ts-to-js/ts/app/hero-di-inject.component.ts, 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-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,
cb-ts-to-js/js/app/hero-di-inject.component.js cb-ts-to-js/js/app/hero-di-inject.component.js
`,` `,
, ',,,,dsl',
, ` TypeScript,
,
parameters,
ctor
`,`
TypeScript,
ES6 JavaScript with decorators, ES6 JavaScript with decorators,
ES6 JavaScript, ES6 JavaScript,
ES5 JavaScript, ES5 JavaScript,
ES5 JavaScript with Class API ES5 JavaScript with DSL
`) `)
:marked :marked
### Additional Injection Decorators ### Additional Injection Decorators
You can attach additional decorators to constructor parameters to qualify the injection behavior. You can qualify injection behavior with injection decorators from `@angular/core`.
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)).
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 In _plain ES6_ and _ES5_, create an instance of the equivalent injection qualifier in a nested array within the `parameters` array.
array notation in which the injection information precedes the constructor function itself. For example, you'd write `new Optional()` in _plain ES6_ and `new ng.core.Optional()` in _ES5_.
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.
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.
+makeTabs(` +makeTabs(`
cb-ts-to-js/ts/app/hero-di-inject-additional.component.ts, cb-ts-to-js/ts/app/hero-title.component.ts,
cb-ts-to-js/js-es6-decorators/app/hero-di-inject-additional.component.es6, cb-ts-to-js/js-es6-decorators/app/hero-title.component.es6,
cb-ts-to-js/js-es6/app/hero-di-inject-additional.component.es6, cb-ts-to-js/js-es6/app/hero-title.component.es6,
cb-ts-to-js/js/app/hero-di-inject-additional.component.js cb-ts-to-js/js/app/hero-title.component.js,
`,` cb-ts-to-js/js/app/hero-title.component.js
`,` `,
TypeScript, ',,,,dsl',
` TypeScript,
ES6 JavaScript with decorators, ES6 JavaScript with decorators,
ES6 JavaScript, 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 .l-main-section
:marked :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 ### 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. element to a component or directive.
The [`@HostBinding`](../api/core/index/HostBinding-interface.html) decorator The [`@HostBinding`](../api/core/index/HostBinding-interface.html) decorator
binds host element properties to component data properties. binds host element properties to component data properties.
The [`@HostListener`](../api/core/index/HostListener-interface.html) decorator binds The [`@HostListener`](../api/core/index/HostListener-interface.html) decorator binds
host element events to component event handlers. 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`. same effect as `@HostBinding` and `@HostListener`.
The `host` value is an object whose properties are host property and listener bindings: 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. * Each value identifies the corresponding component property or method.
+makeTabs(` +makeTabs(`
cb-ts-to-js/ts/app/heroes-bindings.component.ts, cb-ts-to-js/ts/app/hero-host.component.ts,
cb-ts-to-js/js-es6-decorators/app/heroes-bindings.component.es6, cb-ts-to-js/js-es6-decorators/app/hero-host.component.es6,
cb-ts-to-js/js-es6/app/heroes-bindings.component.es6, cb-ts-to-js/js-es6/app/hero-host.component.es6,
cb-ts-to-js/js/app/heroes-bindings.component.js cb-ts-to-js/js/app/hero-host.component.js,
`,` cb-ts-to-js/js/app/hero-host.component.js
`,` `,
TypeScript, ',,,,dsl',
` TypeScript,
ES6 JavaScript with decorators, ES6 JavaScript with decorators,
ES6 JavaScript, 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 :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_.
There are several property decorators for querying the descendants of The following re-implementation of the `HeroComponent` reminds us that _any property metadata decorator_
a component or directive. 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
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 The [`@ViewChild`](../api/core/index/ViewChild-decorator.html) and
[`@ViewChildren`](../api/core/index/ViewChildren-decorator.html) property decorators [`@ViewChildren`](../api/core/index/ViewChildren-decorator.html) property decorators
allow a component to query instances of other components that are used in allow a component to query instances of other components that are used in
its view. its view.
In _ES5_/_ES6_ JavaScript you access a component's view children by adding a `queries` attribute to In _ES5_ and _ES6_, you access a component's view children by adding a `queries` property to the component metadata.
the component metadata. It should be an object where: The `queries` property value is a hash map.
* Each key is the name of a component property that will hold the view children * each _key_ is the name of a component property that will hold the view child or children.
* Each value is an instance of either `ViewChild` or `ViewChildren`. * each _value_ is a new instance of either `ViewChild` or `ViewChildren`.
+makeTabs(` +makeTabs(`
cb-ts-to-js/ts/app/heroes-queries.component.ts, cb-ts-to-js/ts/app/hero-queries.component.ts,
cb-ts-to-js/js-es6-decorators/app/heroes-queries.component.es6, cb-ts-to-js/js-es6-decorators/app/hero-queries.component.es6,
cb-ts-to-js/js-es6/app/heroes-queries.component.es6, cb-ts-to-js/js-es6/app/hero-queries.component.es6,
cb-ts-to-js/js/app/heroes-queries.component.js cb-ts-to-js/js/app/hero-queries.component.js
`,` `,
view, 'view, view, view, view',
view, ` TypeScript,
view,
view
`,`
TypeScript,
ES6 JavaScript with decorators, ES6 JavaScript with decorators,
ES6 JavaScript, ES6 JavaScript,
ES5 JavaScript ES5 JavaScript with DSL
`) `)
:marked :marked
@ -560,22 +640,23 @@ a#host-query-metadata
[`@ViewChildren`](../api/core/index/ViewChildren-decorator.html). [`@ViewChildren`](../api/core/index/ViewChildren-decorator.html).
+makeTabs(` +makeTabs(`
cb-ts-to-js/ts/app/heroes-queries.component.ts, cb-ts-to-js/ts/app/hero-queries.component.ts,
cb-ts-to-js/js-es6-decorators/app/heroes-queries.component.es6, cb-ts-to-js/js-es6-decorators/app/hero-queries.component.es6,
cb-ts-to-js/js-es6/app/heroes-queries.component.es6, cb-ts-to-js/js-es6/app/hero-queries.component.es6,
cb-ts-to-js/js/app/heroes-queries.component.js cb-ts-to-js/js/app/hero-queries.component.js
`,` `,
content, 'content, content, content, content',
content, ` TypeScript,
content,
content
`,`
TypeScript,
ES6 JavaScript with decorators, ES6 JavaScript with decorators,
ES6 JavaScript, 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 a#aot
.l-main-section .l-main-section
:marked :marked