diff --git a/public/docs/_examples/pipes/e2e-spec.js b/public/docs/_examples/pipes/e2e-spec.js index a8637947d0..4f07ce7137 100644 --- a/public/docs/_examples/pipes/e2e-spec.js +++ b/public/docs/_examples/pipes/e2e-spec.js @@ -5,19 +5,19 @@ describe('Pipes', function () { }); it('should open correctly', function () { - expect(element.all(by.css('h4')).get(0).getText()).toEqual('Hero Birthday v.1'); - expect(element(by.css('body > hero-birthday p')).getText()).toEqual("The hero's birthday is Apr 15, 1988"); + expect(element.all(by.tagName('h1')).get(0).getText()).toEqual('Pipes'); + expect(element(by.css('hero-birthday p')).getText()).toEqual("The hero's birthday is Apr 15, 1988"); }); - it('should show delayed message', function () { - expect(element.all(by.css('hero-message')).get(0).getText()).toEqual('Message: You are my Hero!'); + it('should show an async hero message', function () { + expect(element.all(by.tagName('hero-message')).get(0).getText()).toContain('hero'); }); it('should show 4 heroes', function () { expect(element.all(by.css('hero-list div')).count()).toEqual(4); }); - it('should show 4 heroes in json', function () { + it('should show a familiar hero in json', function () { expect(element(by.cssContainingText('hero-list p', 'Heroes as JSON')).getText()).toContain('Bombasto'); }); @@ -27,9 +27,9 @@ describe('Pipes', function () { }); it('should be able to toggle birthday formats', function () { - var birthDayEle = element(by.css('my-app > hero-birthday > p')); + var birthDayEle = element(by.css('hero-birthday2 > p')); expect(birthDayEle.getText()).toEqual("The hero's birthday is 4/15/1988"); - var buttonEle = element(by.cssContainingText('my-app > hero-birthday > button', "Toggle Format")); + var buttonEle = element(by.cssContainingText('hero-birthday2 > button', "Toggle Format")); expect(buttonEle.isDisplayed()).toBe(true); buttonEle.click().then(function() { expect(birthDayEle.getText()).toEqual("The hero's birthday is Friday, April 15, 1988"); @@ -66,5 +66,52 @@ describe('Pipes', function () { }); + it('should support flying heroes (pure) ', function () { + var nameEle = element(by.css('flying-heroes input[type="text"]')); + var canFlyCheckEle = element(by.css('flying-heroes #can-fly')); + var mutateCheckEle = element(by.css('flying-heroes #mutate')); + var resetEle = element(by.css('flying-heroes button')); + var flyingHeroesEle = element.all(by.css('flying-heroes #flyers div')); + + expect(canFlyCheckEle.getAttribute('checked')).toEqual('true', 'should default to "can fly"'); + expect(mutateCheckEle.getAttribute('checked')).toEqual('true', 'should default to mutating array'); + expect(flyingHeroesEle.count()).toEqual(2, 'only two of the original heroes can fly'); + + return sendKeys(nameEle, "test1\n") + .then(function(){ + expect(flyingHeroesEle.count()).toEqual(2, 'no change while mutating array'); + return mutateCheckEle.click(); + }) + .then(function() { + return sendKeys(nameEle, "test2\n"); + }) + .then(function() { + expect(flyingHeroesEle.count()).toEqual(4, 'not mutating; should see both adds'); + expect(flyingHeroesEle.get(2).getText()).toContain('test1'); + expect(flyingHeroesEle.get(3).getText()).toContain('test2'); + return resetEle.click(); + }) + .then(function() { + expect(flyingHeroesEle.count()).toEqual(2, 'reset should restore orginal flying heroes'); + }) + }); + + + it('should support flying heroes (impure) ', function () { + var nameEle = element(by.css('flying-heroes-impure input[type="text"]')); + var canFlyCheckEle = element(by.css('flying-heroes-impure #can-fly')); + var mutateCheckEle = element(by.css('flying-heroes-impure #mutate')); + var resetEle = element(by.css('flying-heroes-impure button')); + var flyingHeroesEle = element.all(by.css('flying-heroes-impure #flyers div')); + + expect(canFlyCheckEle.getAttribute('checked')).toEqual('true', 'should default to "can fly"'); + expect(mutateCheckEle.getAttribute('checked')).toEqual('true', 'should default to mutating array'); + expect(flyingHeroesEle.count()).toEqual(2, 'only two of the original heroes can fly'); + + return sendKeys(nameEle, "test1\n") + .then(function(){ + expect(flyingHeroesEle.count()).toEqual(3, 'new flying hero should show in mutating array'); + }) + }); }); diff --git a/public/docs/_examples/pipes/ts/app/app.component.html b/public/docs/_examples/pipes/ts/app/app.component.html index 7cbc969c84..f86ef24338 100644 --- a/public/docs/_examples/pipes/ts/app/app.component.html +++ b/public/docs/_examples/pipes/ts/app/app.component.html @@ -1,11 +1,26 @@ -
- - + +

Pipes

+Happy Birthday v.1
+Birthday DatePipe
+Happy Birthday v.2
+Birthday Pipe Chaining
+Power Booster custom pipe
+Power Boost Calculator custom pipe with params
+Flying Heroes filter pipe (pure)
+Flying Heroes filter pipe (impure)
+Async Hero Message and AsyncPipe
+Hero List with caching FetchJsonPipe
+Random Pipe (pure pipe / impure function)
+
- + +

Hero Birthday v.1

+
+ +

Birthday DatePipe

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

@@ -15,33 +30,59 @@
-

Hero Birthday v.2

-loading... + +

Hero Birthday v.2

+ +
- - - + +

Birthday Pipe Chaining

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

+

-

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

- +

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

+


-loading... + +
-loading .. + +loading +
+ + + +
+ + + +
+ + + + +
+ + + +
+ + + +
diff --git a/public/docs/_examples/pipes/ts/app/app.component.ts b/public/docs/_examples/pipes/ts/app/app.component.ts index db6a0c7a81..015715cc7e 100644 --- a/public/docs/_examples/pipes/ts/app/app.component.ts +++ b/public/docs/_examples/pipes/ts/app/app.component.ts @@ -1,20 +1,30 @@ // #docregion import {Component} from 'angular2/core'; +import {HTTP_PROVIDERS} from 'angular2/http'; + +import {FlyingHeroesComponent, + FlyingHeroesImpureComponent} from './flying-heroes.component'; import {HeroAsyncMessageComponent} from './hero-async-message.component'; -import {HeroBirthday} from './hero-birthday2.component'; +import {HeroBirthday} from './hero-birthday1.component'; +import {HeroBirthday2} from './hero-birthday2.component'; import {HeroListComponent} from './hero-list.component'; import {PowerBooster} from './power-booster.component'; import {PowerBoostCalculator} from './power-boost-calculator.component'; +import {RandomPipeComponent} from './random-pipe.component'; @Component({ selector: 'my-app', templateUrl: 'app/app.component.html', directives:[ + FlyingHeroesComponent, FlyingHeroesImpureComponent, HeroAsyncMessageComponent, HeroBirthday, + HeroBirthday2, HeroListComponent, - PowerBooster, PowerBoostCalculator - ] + PowerBooster, PowerBoostCalculator, + RandomPipeComponent + ], + providers:[HTTP_PROVIDERS] }) export class AppComponent { birthday = new Date(1988,3,15); // April 15, 1988 diff --git a/public/docs/_examples/pipes/ts/app/exponential-strength.pipe.ts b/public/docs/_examples/pipes/ts/app/exponential-strength.pipe.ts index 2907cd00dd..7164086f21 100644 --- a/public/docs/_examples/pipes/ts/app/exponential-strength.pipe.ts +++ b/public/docs/_examples/pipes/ts/app/exponential-strength.pipe.ts @@ -11,8 +11,8 @@ import {Pipe, PipeTransform} from 'angular2/core'; */ @Pipe({name: 'exponentialStrength'}) export class ExponentialStrengthPipe implements PipeTransform { - - transform(value:number, args:string[]) : any { - return Math.pow(value, parseInt(args[0] || '1', 10)); + transform(value:number, [exponent]) : number { + var exp = parseFloat(exponent); + return Math.pow(value, isNaN(exp) ? 1 : exp); } } diff --git a/public/docs/_examples/pipes/ts/app/fetch-json.pipe.ts b/public/docs/_examples/pipes/ts/app/fetch-json.pipe.ts index 9383ce0990..99cae3fc09 100644 --- a/public/docs/_examples/pipes/ts/app/fetch-json.pipe.ts +++ b/public/docs/_examples/pipes/ts/app/fetch-json.pipe.ts @@ -1,6 +1,6 @@ -/// // #docregion import {Pipe, PipeTransform} from 'angular2/core'; +import {Http} from 'angular2/http'; // #docregion pipe-metadata @Pipe({ @@ -9,16 +9,20 @@ import {Pipe, PipeTransform} from 'angular2/core'; }) // #enddocregion pipe-metadata export class FetchJsonPipe implements PipeTransform{ - private fetchedValue:any; - private fetchPromise:Promise; + private fetched:any = null; + private prevUrl = ''; - transform(value:string, args:string[]):any { - if (!this.fetchPromise) { - this.fetchPromise = window.fetch(value) - .then((result:any) => result.json()) - .then((json:any) => this.fetchedValue = json); + constructor(private _http: Http) { } + + transform(url:string):any { + if (url !== this.prevUrl) { + this.prevUrl = url; + this.fetched = null; + this._http.get(url) + .map( result => result.json() ) + .subscribe( result => this.fetched = result ) } - return this.fetchedValue; + return this.fetched; } -} \ No newline at end of file +} diff --git a/public/docs/_examples/pipes/ts/app/flying-heroes.component.html b/public/docs/_examples/pipes/ts/app/flying-heroes.component.html new file mode 100644 index 0000000000..b6beb80fee --- /dev/null +++ b/public/docs/_examples/pipes/ts/app/flying-heroes.component.html @@ -0,0 +1,39 @@ + + +

{{title}}

+

+ +New hero: + + + can fly +

+

+ Mutate array + + + +

+ +

Heroes who fly (piped)

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

All Heroes (no pipe)

+
+ + +
+ {{hero.name}} +
+ + + +
diff --git a/public/docs/_examples/pipes/ts/app/flying-heroes.component.ts b/public/docs/_examples/pipes/ts/app/flying-heroes.component.ts new file mode 100644 index 0000000000..dcb3d812f8 --- /dev/null +++ b/public/docs/_examples/pipes/ts/app/flying-heroes.component.ts @@ -0,0 +1,64 @@ +// #docplaster +// #docregion +import {Component} from 'angular2/core'; +import {FlyingHeroesPipe, + FlyingHeroesImpurePipe} from './flying-heroes.pipe'; +import {HEROES} from './heroes'; + +@Component({ + selector: 'flying-heroes', + templateUrl: 'app/flying-heroes.component.html', + styles: ['#flyers, #all {font-style: italic}'], + pipes: [FlyingHeroesPipe] +}) +// #docregion v1 +export class FlyingHeroesComponent { + heroes:any[] = []; + canFly = true; +// #enddocregion v1 + mutate = true; + title = 'Flying Heroes (pure pipe)'; + +// #docregion v1 + constructor() { this.reset(); } + + addHero(name:string) { + name = name.trim(); + if (!name) { return; } + let hero = {name, canFly: this.canFly}; +// #enddocregion v1 + if (this.mutate) { + // Pure pipe won't update display because heroes array reference is unchanged + // Impure pipe will display +// #docregion v1 +// #docregion push + this.heroes.push(hero) +// #enddocregion push +// #enddocregion v1 + } else { + // Pipe updates display because heroes array is a new object +// #docregion concat + this.heroes = this.heroes.concat(hero); +// #enddocregion concat + } +// #docregion v1 + } + + reset() { this.heroes = HEROES.slice(); } +} +// #enddocregion v1 + +////// Identical except for impure pipe ////// +// #docregion impure-component +@Component({ + selector: 'flying-heroes-impure', + templateUrl: 'app/flying-heroes.component.html', +// #enddocregion impure-component + styles: ['.flyers, .all {font-style: italic}'], +// #docregion impure-component + pipes: [FlyingHeroesImpurePipe] +}) +export class FlyingHeroesImpureComponent extends FlyingHeroesComponent { + title = 'Flying Heroes (impure pipe)'; +} +// #docregion impure-component diff --git a/public/docs/_examples/pipes/ts/app/flying-heroes.pipe.ts b/public/docs/_examples/pipes/ts/app/flying-heroes.pipe.ts new file mode 100644 index 0000000000..c03fe02a3a --- /dev/null +++ b/public/docs/_examples/pipes/ts/app/flying-heroes.pipe.ts @@ -0,0 +1,25 @@ +// #docregion +// #docregion pure +import {Flyer} from './heroes'; +import {Pipe, PipeTransform} from 'angular2/core'; + +@Pipe({ name: 'flyingHeroes' }) +export class FlyingHeroesPipe implements PipeTransform { + transform(allHeroes:Flyer[]) { + // #docregion filter + return allHeroes.filter(hero => hero.canFly); + // #enddocregion filter + } +} +// #enddocregion pure + +/////// Identical except for the pure flag +// #docregion impure +// #docregion pipe-decorator +@Pipe({ + name: 'flyingHeroes', + pure: false +}) +// #enddocregion pipe-decorator +export class FlyingHeroesImpurePipe extends FlyingHeroesPipe {} +// #enddocregion impure diff --git a/public/docs/_examples/pipes/ts/app/hero-async-message.component.ts b/public/docs/_examples/pipes/ts/app/hero-async-message.component.ts index 9303932d41..a5a00bfb2f 100644 --- a/public/docs/_examples/pipes/ts/app/hero-async-message.component.ts +++ b/public/docs/_examples/pipes/ts/app/hero-async-message.component.ts @@ -1,15 +1,39 @@ // #docregion import {Component} from 'angular2/core'; +import {Observable} from 'rxjs/Rx'; // Initial view: "Message: " // After 500ms: Message: You are my Hero!" @Component({ selector: 'hero-message', - template: 'Message: {{delayedMessage | async}}', + template: ` +

Async Hero Message and AsyncPipe

+ +

Message: {{ message$ | async }}

+ + `, }) export class HeroAsyncMessageComponent { - delayedMessage:Promise = new Promise((resolve, reject) => { - setTimeout(() => resolve('You are my Hero!'), 500); - }); + message$:Observable; + + constructor() { this.resend(); } + + resend() { + this.message$ = Observable.interval(500) + .map(i => this.messages[i]) + .take(this.messages.length); + } + + private messages = [ + 'You are my hero!', + 'You are the best hero!', + 'Will you be my hero?' + ]; } +// #enddocregion + +// Alternative message$ formula: +// this.message$ = Observable.fromArray(this.messages) +// .map(message => Observable.timer(500).map(() => message)) +// .concatAll(); diff --git a/public/docs/_examples/pipes/ts/app/hero-birthday2.component.ts b/public/docs/_examples/pipes/ts/app/hero-birthday2.component.ts index e0b357c7f4..6aef612778 100644 --- a/public/docs/_examples/pipes/ts/app/hero-birthday2.component.ts +++ b/public/docs/_examples/pipes/ts/app/hero-birthday2.component.ts @@ -3,7 +3,7 @@ import {Component} from 'angular2/core' @Component({ - selector: 'hero-birthday', + selector: 'hero-birthday2', // #docregion template template: `

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

@@ -12,13 +12,11 @@ import {Component} from 'angular2/core' // #enddocregion template }) // #docregion class -export class HeroBirthday { +export class HeroBirthday2 { birthday = new Date(1988,3,15); // April 15, 1988 - toggle = true; // start with true == shortDate - get format() { return this.toggle ? 'shortDate' : 'fullDate'} - + get format() { return this.toggle ? 'shortDate' : 'fullDate'} toggleFormat() { this.toggle = !this.toggle; } } // #enddocregion class diff --git a/public/docs/_examples/pipes/ts/app/hero-list.component.ts b/public/docs/_examples/pipes/ts/app/hero-list.component.ts index 169767eac1..414281e6e6 100644 --- a/public/docs/_examples/pipes/ts/app/hero-list.component.ts +++ b/public/docs/_examples/pipes/ts/app/hero-list.component.ts @@ -6,7 +6,7 @@ import {FetchJsonPipe} from './fetch-json.pipe'; selector: 'hero-list', // #docregion template template: ` -

Heroes from JSON File

+

Heroes from JSON File

{{hero.name}} @@ -19,6 +19,4 @@ import {FetchJsonPipe} from './fetch-json.pipe'; // #enddocregion template pipes: [FetchJsonPipe] }) -export class HeroListComponent { - /* I've got nothing to do ;-) */ -} +export class HeroListComponent { } diff --git a/public/docs/_examples/pipes/ts/app/heroes.ts b/public/docs/_examples/pipes/ts/app/heroes.ts new file mode 100644 index 0000000000..fe30ad84f4 --- /dev/null +++ b/public/docs/_examples/pipes/ts/app/heroes.ts @@ -0,0 +1,7 @@ +export interface Flyer { canFly: boolean } +export const HEROES = [ + {"name": "Windstorm", "canFly": true}, + {"name": "Bombasto", "canFly": false}, + {"name": "Magneto", "canFly": false}, + {"name": "Tornado", "canFly": true} +]; \ No newline at end of file diff --git a/public/docs/_examples/pipes/ts/app/main.ts b/public/docs/_examples/pipes/ts/app/main.ts index 597ab3aa7c..fd7c63a8a2 100644 --- a/public/docs/_examples/pipes/ts/app/main.ts +++ b/public/docs/_examples/pipes/ts/app/main.ts @@ -1,6 +1,6 @@ import {bootstrap} from 'angular2/platform/browser'; +import 'rxjs/Rx'; + import {AppComponent} from './app.component'; -import {HeroBirthday} from './hero-birthday1.component'; bootstrap(AppComponent); -bootstrap(HeroBirthday); // v.1 \ No newline at end of file diff --git a/public/docs/_examples/pipes/ts/app/random-pipe.component.ts b/public/docs/_examples/pipes/ts/app/random-pipe.component.ts new file mode 100644 index 0000000000..fe86108432 --- /dev/null +++ b/public/docs/_examples/pipes/ts/app/random-pipe.component.ts @@ -0,0 +1,24 @@ +import {Component} from 'angular2/core'; +import {Pipe, PipeTransform} from 'angular2/core'; + +// #docregion pipe +// Pure pipe +@Pipe({ name: 'randomizer' }) +export class RandomizerPipe implements PipeTransform { + // Impure function + transform() { return Math.random() * 10 ;} +} +// #enddocregion pipe + +@Component({ + selector: 'random-pipe', + template: ` +

Random Pipe (pure pipe/impure function)

+ +

Input value: {{box.value}}

+

Random pipe output: {{box.value | randomizer}}

+ `, + pipes: [RandomizerPipe] +}) +export class RandomPipeComponent { +} diff --git a/public/docs/_examples/pipes/ts/app/window.extension.d.ts b/public/docs/_examples/pipes/ts/app/window.extension.d.ts deleted file mode 100644 index 0a5a71bbf6..0000000000 --- a/public/docs/_examples/pipes/ts/app/window.extension.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -interface Window { - fetch(url: string, options? : {}) : Promise -} diff --git a/public/docs/_examples/pipes/ts/heroes.json b/public/docs/_examples/pipes/ts/heroes.json index 436b220d53..e5f0b77262 100644 --- a/public/docs/_examples/pipes/ts/heroes.json +++ b/public/docs/_examples/pipes/ts/heroes.json @@ -1,6 +1,6 @@ [ - {"name": "Windstorm"}, - {"name": "Bombasto"}, - {"name": "Magneto"}, - {"name": "Tornado"} + {"name": "Windstorm", "canFly": true}, + {"name": "Bombasto", "canFly": false}, + {"name": "Magneto", "canFly": false}, + {"name": "Tornado", "canFly": true} ] diff --git a/public/docs/_examples/pipes/ts/index.html b/public/docs/_examples/pipes/ts/index.html index f11eba1c67..498e376a5e 100644 --- a/public/docs/_examples/pipes/ts/index.html +++ b/public/docs/_examples/pipes/ts/index.html @@ -9,14 +9,15 @@ - + +