diff --git a/public/docs/_examples/pipes/ts/.gitignore b/public/docs/_examples/pipes/ts/.gitignore new file mode 100644 index 0000000000..6724ce3596 --- /dev/null +++ b/public/docs/_examples/pipes/ts/.gitignore @@ -0,0 +1 @@ +src/**/*.js \ No newline at end of file diff --git a/public/docs/_examples/pipes/ts/package.json b/public/docs/_examples/pipes/ts/package.json new file mode 100644 index 0000000000..7ba2b6bc56 --- /dev/null +++ b/public/docs/_examples/pipes/ts/package.json @@ -0,0 +1,21 @@ +{ + "name": "angular2-pipes", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "tsc": "tsc -p src -w", + "start": "live-server --open=src" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "angular2": "2.0.0-alpha.44", + "systemjs": "0.19.2" + }, + "devDependencies": { + "live-server": "^0.8.1", + "typescript": "^1.6.2" + } +} diff --git a/public/docs/_examples/pipes/ts/src/app/app.html b/public/docs/_examples/pipes/ts/src/app/app.html new file mode 100644 index 0000000000..bcaf614709 --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/app.html @@ -0,0 +1,46 @@ + + + +
+ + + +
+ + +

The hero's birthday is {{ birthday | date }}

+ + + +

The hero's birthday is {{ birthday | date:"MM/dd/yy" }} /p> + + +


+ +

Hero Birthday 2

+loading... +
+ + + +

+ The chained hero's birthday is + {{ birthday | date | uppercase}} +

+ + + +

+ The chained hero's birthday is + {{ ( birthday | date:'fullDate' ) | uppercase}} +

+ + +
+ +loading... + +
+ +loading .. + diff --git a/public/docs/_examples/pipes/ts/src/app/app.ts b/public/docs/_examples/pipes/ts/src/app/app.ts new file mode 100644 index 0000000000..29bf1b84ed --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/app.ts @@ -0,0 +1,52 @@ +import {HeroBirthday as HeroBirthday2} from './hero-birthday.2'; +import {PowerBooster} from './power-booster'; +import {PowerBoostCalculator} from './power-boost-calculator'; +import {HeroListComponent} from './hero-list-component'; + +// #docregion hero-birthday +import {bootstrap, Component} from 'angular2/angular2' + +@Component({ + selector: 'hero-birthday', + // #docregion hero-birthday-template + template: `

The hero's birthday is {{ birthday | date }}

` + // #enddocregion hero-birthday-template +}) +export class HeroBirthday { + birthday = new Date(1988,3,15); // April 15, 1988 +} + +bootstrap(HeroBirthday); +// #enddocregion hero-birthday + +// #docregion async-message +@Component({ + selector: 'my-hero', + template: 'Message: {{delayedMessage | async}}', +}) +class MyHeroAsyncMessageComponent { + delayedMessage:Promise = new Promise((resolve, reject) => { + setTimeout(() => resolve('You are my Hero!'), 500); + }); +} + +// Initial view: "Message: " +// After 500ms: Message: You are my Hero!" +// #enddocregion async-message + +//// Drives the rest of the pipes chapter examples /// + +@Component({ + selector: 'my-app', + templateUrl: 'app/app.html', + directives:[ + HeroBirthday2, + PowerBooster, PowerBoostCalculator, + MyHeroAsyncMessageComponent, + HeroListComponent] +}) +class AppComponent { + birthday = new Date(1988,3,15); // April 15, 1988 +} +bootstrap(AppComponent); + \ No newline at end of file diff --git a/public/docs/_examples/pipes/ts/src/app/exponential-strength-pipe.ts b/public/docs/_examples/pipes/ts/src/app/exponential-strength-pipe.ts new file mode 100644 index 0000000000..bed8e2dd2e --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/exponential-strength-pipe.ts @@ -0,0 +1,21 @@ +// #docregion +import {Pipe} from 'angular2/angular2'; +/* + * Raise the value exponentially + * Takes an exponent argument that defaults to 1. + * Usage: + * value | exponentialStrength:exponent + * Example: + * {{ 2 | exponentialStrength:10}} + * formats to: 1024 +*/ +@Pipe({ + name: 'exponentialStrength' +}) +export class ExponentialStrengthPipe { + + transform(value:number, args:string[]) : any { + return Math.pow(value, parseInt(args[0] || '1', 10)); + } +} +// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/pipes/ts/src/app/fetch-json-pipe.ts b/public/docs/_examples/pipes/ts/src/app/fetch-json-pipe.ts new file mode 100644 index 0000000000..a1c61e538b --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/fetch-json-pipe.ts @@ -0,0 +1,26 @@ +/// + +// #docregion +import {Pipe} from 'angular2/angular2'; + +// #docregion pipe-metadata +@Pipe({ + name: 'fetch', + pure: false +}) +// #enddocregion pipe-metadata +export class FetchJsonPipe { + private fetchedValue:any; + private fetchPromise:Promise; + transform(value:string, args:string[]):any { + if (!this.fetchPromise) { + this.fetchPromise = window.fetch(value) + .then(result => result.json()) + .then(json => { + this.fetchedValue = json; + }); + } + + return this.fetchedValue; + } +} \ No newline at end of file diff --git a/public/docs/_examples/pipes/ts/src/app/hero-birthday.2.ts b/public/docs/_examples/pipes/ts/src/app/hero-birthday.2.ts new file mode 100644 index 0000000000..62a3da08bc --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/hero-birthday.2.ts @@ -0,0 +1,16 @@ +import {bootstrap, Component} from 'angular2/angular2' +// #docregion hero-birthday2 +@Component({ + selector: 'hero-birthday', + template: ` +

The hero's birthday is {{ birthday | date:format }}

+ + ` +}) +export class HeroBirthday { + birthday = new Date(1988,3,15); // April 15, 1988 + get format() { return this.toggle ? 'shortDate' : 'fullDate'} + toggle = true; + toggleFormat() { this.toggle = !this.toggle; } +} +// #enddocregion hero-birthday2 diff --git a/public/docs/_examples/pipes/ts/src/app/hero-list-component.ts b/public/docs/_examples/pipes/ts/src/app/hero-list-component.ts new file mode 100644 index 0000000000..7d4e0974e7 --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/hero-list-component.ts @@ -0,0 +1,25 @@ +// #docregion +import {bootstrap, Component, + CORE_DIRECTIVES, FORM_DIRECTIVES} from 'angular2/angular2' + +import {FetchJsonPipe} from './fetch-json-pipe' + +@Component({ + selector: 'hero-list', + template: ` +

Heroes from JSON File

+ +
+ {{hero.name}} +
+ +

Heroes as JSON: + {{'heroes.json' | fetch | json}} +

+ `, + directives:[CORE_DIRECTIVES], + pipes: [FetchJsonPipe] +}) +export class HeroListComponent { + /* I've got nothing to do ;-) */ +} diff --git a/public/docs/_examples/pipes/ts/src/app/power-boost-calculator.ts b/public/docs/_examples/pipes/ts/src/app/power-boost-calculator.ts new file mode 100644 index 0000000000..7ffad97c7e --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/power-boost-calculator.ts @@ -0,0 +1,21 @@ +// #docregion +import {Component, FORM_DIRECTIVES} from 'angular2/angular2' +import {ExponentialStrengthPipe} from './exponential-strength-pipe' + +@Component({ + selector: 'power-boost-calculator', + template: ` +

Power Boost Calculator

+
Normal power:
+
Boost factor:
+

+ Super Hero Power: {{power | exponentialStrength: factor}} +

+ `, + pipes: [ExponentialStrengthPipe], + directives: [FORM_DIRECTIVES] +}) +export class PowerBoostCalculator { + power = 5; + factor = 1; +} diff --git a/public/docs/_examples/pipes/ts/src/app/power-booster.ts b/public/docs/_examples/pipes/ts/src/app/power-booster.ts new file mode 100644 index 0000000000..071dbb0a75 --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/power-booster.ts @@ -0,0 +1,15 @@ +// #docregion +import {Component} from 'angular2/angular2' +import {ExponentialStrengthPipe} from './exponential-strength-pipe' + +@Component({ + selector: 'power-booster', + template: ` +

Power Booster

+

+ Super power boost: {{2 | exponentialStrength: 10}} +

+ `, + pipes: [ExponentialStrengthPipe] +}) +export class PowerBooster { } diff --git a/public/docs/_examples/pipes/ts/src/app/window.extension.d.ts b/public/docs/_examples/pipes/ts/src/app/window.extension.d.ts new file mode 100644 index 0000000000..c9ffbfb25a --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/window.extension.d.ts @@ -0,0 +1,3 @@ +interface Window { + fetch:(url: string, options?: {}) => Promise +} \ No newline at end of file diff --git a/public/docs/_examples/pipes/ts/src/heroes.json b/public/docs/_examples/pipes/ts/src/heroes.json new file mode 100644 index 0000000000..436b220d53 --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/heroes.json @@ -0,0 +1,6 @@ +[ + {"name": "Windstorm"}, + {"name": "Bombasto"}, + {"name": "Magneto"}, + {"name": "Tornado"} +] diff --git a/public/docs/_examples/pipes/ts/src/index.html b/public/docs/_examples/pipes/ts/src/index.html new file mode 100644 index 0000000000..30242dceae --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/index.html @@ -0,0 +1,23 @@ + + + + + Pipes + + + + + + +

Hero Birthday 1

+ loading... +
+ loading ... + + + diff --git a/public/docs/_examples/pipes/ts/src/tsconfig.json b/public/docs/_examples/pipes/ts/src/tsconfig.json new file mode 100644 index 0000000000..6a58b35a58 --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "ES5", + "module": "commonjs", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "removeComments": false, + "noImplicitAny": false + } +} \ No newline at end of file diff --git a/public/docs/ts/latest/guide/pipes.jade b/public/docs/ts/latest/guide/pipes.jade index 446ef17493..4419859e74 100644 --- a/public/docs/ts/latest/guide/pipes.jade +++ b/public/docs/ts/latest/guide/pipes.jade @@ -4,7 +4,7 @@ include ../../../../_includes/_util-fns Getting data could be as simple as creating a local variable or as complex as streaming data over a Websocket. - Once data arrive, we could plaster them directly to screen. + Once data arrive, we could push their raw `toString` values directly to screen. That rarely makes for a good user experience. Almost everyone prefers a simple birthday date (April 15, 1988) to the original raw string format @@ -30,23 +30,13 @@ include ../../../../_includes/_util-fns All date samples are in my plunker http://plnkr.co/edit/RDlOma?p=preview --> -code-example(format="linenums" escape="html"). - import {bootstrap, Component} from 'angular2/angular2' - @Component({ - selector: 'hero-birthday', - template: `

The hero's birthday is {{ birthday | date }}

` - }) - class HeroBirthday { - birthday = new Date(1988,3,15); // April 15, 1988 - } - - bootstrap(HeroBirthday); ++makeExample('pipes/ts/src/app/app.ts', 'hero-birthday') + :markdown Focus on the component's template to see how we applied the built-in `DatePipe` while binding the `birthday` property. -code-example(format="linenums" escape="html"). -

The hero's birthday is {{ birthday | date }}

++makeExample('pipes/ts/src/app/app.html', 'hero-birthday-template')(format=".") :markdown Angular [template syntax](./template-syntax.html#pipe) includes a pipe operator ( | ) which we're @@ -75,8 +65,7 @@ code-example(format="linenums" escape="html"). We'll modify our birthday example to give the date pipe a format parameter. The formatted date should display as **04/15/88**. -code-example(format="linenums" escape="html"). -

The hero's birthday is {{ birthday | date:"MM/dd/yy" }}

++makeExample('pipes/ts/src/app/app.html', 'format-birthday')(format=".") :markdown The parameter value can be any valid @@ -85,25 +74,7 @@ code-example(format="linenums" escape="html"). Let's revise our example to bind the pipe's format parameter to the component's `format` property. -code-example(format="linenums" ). - @Component({ - selector: 'hero-birthday', - template: ` - <p>The hero's birthday is {{ birthday | date:format }}</p> - <button (click)="toggleFormat()">Toggle Format</button> - ` - }) - class HeroBirthday { - birthday = new Date(1988,3,15); // April 15, 1988 - format = 'shortDate'; - nextFormat = 'fullDate'; - - toggleFormat() { - let next = this.format; - this.format = this.nextFormat; - this.nextFormat = next; - } - } ++makeExample('pipes/ts/src/app/hero-birthday.2.ts', 'hero-birthday2') :markdown We also added a button to the template and bound its click event to the component's `toggleFormat` method. @@ -111,8 +82,12 @@ code-example(format="linenums" ). ('shortDate') and a longer form ('fullDate'). As we click the button, the displayed date alternates between - "**04/15/88**" and + "**04/15/1988**" and "**Friday, April 15, 1988**". + +figure.image-display + img(src='/resources/images/devguide/pipes/date-format-toggle-anim.gif' alt="Date Format Toggle") +:markdown .l-sub-section :markdown Learn more about the `DatePipes` format options in the [API Docs](../api/core/DatePipe-class.html). @@ -122,23 +97,16 @@ code-example(format="linenums" ). In the following example, we chain the birthday to the `DatePipe` and on to the `UpperCasePipe` so we can display the birthday in uppercase. The following birthday displays as **APR 15, 1988** - -code-example(format="linenums" escape="html"). -

- The chained hero's birthday is - {{ birthday | date | uppercase}} -

+ ++makeExample('pipes/ts/src/app/app.html', 'chained-birthday') + :markdown If we pass a parameter to a filter, we have to add parentheses to help the template compiler with the evaluation order. The following example displays **FRIDAY, APRIL 15, 1988** - -code-example(format="linenums" escape="html"). -

- The chained hero's birthday is - {{ ( birthday | date:'fullDate' ) | uppercase}} -

+ ++makeExample('pipes/ts/src/app/app.html', 'chained-parameter-birthday') .l-sub-section p Future improvements in the template compiler may eliminate the need for parentheses. @@ -147,35 +115,17 @@ code-example(format="linenums" escape="html"). :markdown ## Custom Pipes - We can easily create our own pipes. + We can write our own custom pipes. - Let's create a custom pipe named `ExponentialStrengthPipe` + Let's make a custom pipe named `ExponentialStrengthPipe` that can boost a hero's powers. + + Create a new file, `exponential-strength-pipe.ts`, and enter the following: -code-example(format="linenums" escape="html"). - import {bootstrap, Component, Pipe} from 'angular2/angular2' - - /* - * Raise the value exponentially - * Takes an exponent argument that defaults to 1. - * Usage: - * value | exponentialStrength:exponent - * Example: - * {{ 2 | exponentialStrength:10}} - * formats to: 1024 - */ - @Pipe({ - name: 'exponentialStrength' - }) - class ExponentialStrengthPipe { - - transform(value:number, args:string[]) : any { - return Math.pow(value, parseInt(args[0] || 1, 10)); - } - } + --> ++makeExample('pipes/ts/src/app/exponential-strength-pipe.ts') :markdown This pipe definition reveals several few key points @@ -191,21 +141,10 @@ code-example(format="linenums" escape="html"). * There will be one item in the array for each parameter passed to the pipe * `transform` returns a modified value that Angular converts to a string. - Now let's create a component to demonstrate our pipe and bootstrap it. - -code-example(format="linenums" escape="html"). - @Component({ - selector: 'power-booster', - template: ` -

- Super power boost: {{2 | exponentialStrength: 10}} -

- `, - pipes: [ExponentialStrengthPipe] - }) - class PowerBooster { } - - bootstrap(PowerBooster); + Now let's create a component to demonstrate our pipe. ++makeExample('pipes/ts/src/app/power-booster.ts') +figure.image-display + img(src='/resources/images/devguide/pipes/power-booster.png' alt="Power Booster") :markdown Two things to note: @@ -230,28 +169,11 @@ code-example(format="linenums" escape="html"). We could upgrade the example to a "Power Boost Calculator" that combines our pipe and two-way data binding with `ng-model`. -code-example(format="linenums" ). - import {bootstrap, Component, FORM_DIRECTIVES, Pipe} from 'angular2/angular2' - - @Component({ - selector: 'power-boost-calculator', - template: ` - <h2>Power Boost Calculator</h2> - <div>Normal power: <input [(ng-model)]="power"></div> - <div>Boost factor: <input [(ng-model)]="factor"></div> - <p> - Super Hero Power: {{power | exponentialStrength: factor}} - </p> - `, - pipes: [ExponentialStrengthPipe], - directives: [FORM_DIRECTIVES] - }) - class PowerBoosterCalculator { - power = 5; - factor = 1; - } ++makeExample('pipes/ts/src/app/power-boost-calculator.ts') - bootstrap(PowerBoosterCalculator); +figure.image-display + img(src='/resources/images/devguide/pipes/power-boost-calculator.png' alt="Power Boost Calculator") +:markdown .l-main-section :markdown @@ -276,20 +198,7 @@ code-example(format="linenums" ). It is stateful because the pipe maintains a subscription to the input and its returned values depend on that subscription. In the next example, we bind a simple promise to a view with the async pipe. - -code-example(format="linenums"). - @Component({ - selector: 'my-hero', - template: Message: '{{delayedMessage | async}}', - }) - class MyComponent { - delayedMessage:Promise = new Promise((resolve, reject) => { - setTimeout(() => resolve('You are my Hero!'), 500); - }); - } - - // Initial view: "Message: " - // After 500ms: Message: You are my Hero!" ++makeExample('pipes/ts/src/app/app.ts', 'async-message') :markdown The Async pipe saves boilerplate in the component code. @@ -302,62 +211,27 @@ code-example(format="linenums"). ### Implementing a Stateful Pipe Pipes are stateless by default. We must declare a pipe to be stateful - by setting the “pure” property of the @Pipe decorator to `false`. + by setting the `pure` property of the `@Pipe` decorator to `false`. This setting tells Angular’s change detection system to check the output of this pipe each cycle, whether its input has changed or not. - Here's how we'll decorate our new stateful "FetchJsonPipe" that + Here's how we'll decorate our new stateful `FetchJsonPipe` that makes an HTTP `fetch` request and (eventually) displays the data in the server's response: - - ``` - @Pipe({ - name: 'fetch', - pure: false - }) - ``` - - ++makeExample('pipes/ts/src/app/fetch-json-pipe.ts', 'pipe-metadata') +:markdown Immediately below we have the finished pipe. Its input value is an url to an endpoint that returns a JSON file. The pipe makes a one-time async request to the server and eventually receives the JSON response. ++makeExample('pipes/ts/src/app/fetch-json-pipe.ts') +:markdown + Next we use this pipe in two template bindings where we + 1. display hero names in an `ng-for` repeater + 1. chain the fetched results to the built-in `JsonPipe` that renders + the data in JSON format - ``` - @Pipe({ - name: 'fetch', - pure: false - }) - class FetchJsonPipe { - private fetchedValue:any; - private fetchPromise:Promise; - transform(value:string, args:string[]):any { - if (!this.fetchPromise) { - this.fetchPromise = fetch(value) - .then(result => result.json()) - .then(json => { - this.fetchedValue = json; - }); - } ++makeExample('pipes/ts/src/app/hero-list-component.ts') - return this.fetchedValue; - } - } - ``` - Next we use this pipe in a template binding where we chain the - fetched results to the built-in `JsonPipe` that renders - the data in JSON format: - -code-example(format="linenums" escape="html"). - @Component({ - selector: 'heroes-list' - }) - @View({ - template: ` - Heroes: {{'heroes.json' | fetch | json}} - `, - pipes: [FetchJsonPipe] - }) - class HeroesList { /* I've got nothing to do ;-) */ } - - bootstrap(HeroesList); +figure.image-display + img(src='/resources/images/devguide/pipes/hero-list.png' alt="Hero List") .l-main-section :markdown diff --git a/public/resources/images/devguide/pipes/date-format-toggle-anim.gif b/public/resources/images/devguide/pipes/date-format-toggle-anim.gif new file mode 100644 index 0000000000..379c48df95 Binary files /dev/null and b/public/resources/images/devguide/pipes/date-format-toggle-anim.gif differ diff --git a/public/resources/images/devguide/pipes/hero-list.png b/public/resources/images/devguide/pipes/hero-list.png new file mode 100644 index 0000000000..80e2d15dc7 Binary files /dev/null and b/public/resources/images/devguide/pipes/hero-list.png differ diff --git a/public/resources/images/devguide/pipes/power-boost-calculator.png b/public/resources/images/devguide/pipes/power-boost-calculator.png new file mode 100644 index 0000000000..4155228c33 Binary files /dev/null and b/public/resources/images/devguide/pipes/power-boost-calculator.png differ diff --git a/public/resources/images/devguide/pipes/power-booster.png b/public/resources/images/devguide/pipes/power-booster.png new file mode 100644 index 0000000000..b66792921e Binary files /dev/null and b/public/resources/images/devguide/pipes/power-booster.png differ