| 
									
										
										
										
											2016-01-10 17:07:19 -08:00
										 |  |  | //#docplaster
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 14:06:32 +02:00
										 |  |  | import { AfterViewInit, Component, ElementRef, OnInit, QueryList, ViewChildren } from '@angular/core'; | 
					
						
							|  |  |  | import { NgForm } from '@angular/common'; | 
					
						
							| 
									
										
										
										
											2015-12-07 13:31:26 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 14:06:32 +02:00
										 |  |  | import { Hero } from './hero'; | 
					
						
							|  |  |  | import { HeroDetailComponent, BigHeroDetailComponent } from './hero-detail.component'; | 
					
						
							|  |  |  | import { MyClickDirective, MyClickDirective2 } from './my-click.directive'; | 
					
						
							| 
									
										
										
										
											2015-12-07 13:31:26 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Alerter fn: monkey patch during test
 | 
					
						
							|  |  |  | export function alerter(msg?:string) { | 
					
						
							|  |  |  |   window.alert(msg); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export enum Color {Red, Green, Blue}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Giant grab bag of stuff to drive the chapter | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'my-app', | 
					
						
							|  |  |  |   templateUrl: 'app/app.component.html', | 
					
						
							|  |  |  |   directives: [ | 
					
						
							|  |  |  |     HeroDetailComponent, BigHeroDetailComponent, | 
					
						
							|  |  |  |     MyClickDirective, MyClickDirective2 | 
					
						
							|  |  |  |   ] | 
					
						
							|  |  |  | }) | 
					
						
							| 
									
										
										
										
											2016-02-06 17:18:26 -08:00
										 |  |  | export class AppComponent implements AfterViewInit, OnInit { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ngOnInit(){ | 
					
						
							|  |  |  |     this.refreshHeroes(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ngAfterViewInit() { | 
					
						
							| 
									
										
										
										
											2016-05-03 14:06:32 +02:00
										 |  |  |     this.detectNgForTrackByEffects(); | 
					
						
							| 
									
										
										
										
											2016-02-06 17:18:26 -08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-12-07 13:31:26 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   actionName = 'Go for it'; | 
					
						
							|  |  |  |   alert = alerter; | 
					
						
							| 
									
										
										
										
											2016-01-28 16:01:39 -08:00
										 |  |  |   badCurly = 'bad curly'; | 
					
						
							| 
									
										
										
										
											2016-02-17 10:59:14 -08:00
										 |  |  |   classes = 'special'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-07 13:31:26 -08:00
										 |  |  |   callFax(value:string)   {this.alert(`Faxing ${value} ...`)} | 
					
						
							|  |  |  |   callPhone(value:string) {this.alert(`Calling ${value} ...`)} | 
					
						
							|  |  |  |   canSave =  true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Color = Color; | 
					
						
							|  |  |  |   color = Color.Red; | 
					
						
							|  |  |  |   colorToggle() {this.color = (this.color === Color.Red)? Color.Blue : Color.Red} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   currentHero = Hero.MockHeroes[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-17 10:59:14 -08:00
										 |  |  |   deleteHero(hero:Hero){ | 
					
						
							|  |  |  |     this.alert('Deleted hero: '+ (hero && hero.firstName)) | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-05-03 14:06:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-10 17:07:19 -08:00
										 |  |  |   // DevMode memoization fields
 | 
					
						
							| 
									
										
										
										
											2016-05-03 14:06:32 +02:00
										 |  |  |   private priorClasses:{}; | 
					
						
							| 
									
										
										
										
											2016-01-10 17:07:19 -08:00
										 |  |  |   private _priorStyles:{}; | 
					
						
							|  |  |  |   private _priorStyles2:{}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-07 13:31:26 -08:00
										 |  |  |   getStyles(el:Element){ | 
					
						
							|  |  |  |     let styles = window.getComputedStyle(el); | 
					
						
							|  |  |  |     let showStyles = {}; | 
					
						
							|  |  |  |     for (var p in this.setStyles()){ | 
					
						
							|  |  |  |       showStyles[p] = styles[p]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return JSON.stringify(showStyles); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getVal() {return this.val}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-06 17:18:26 -08:00
										 |  |  |   heroes:Hero[]; | 
					
						
							| 
									
										
										
										
											2015-12-07 13:31:26 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // heroImageUrl = 'http://www.wpclipart.com/cartoon/people/hero/hero_silhoutte_T.png';
 | 
					
						
							|  |  |  |   // Public Domain terms of use: http://www.wpclipart.com/terms.html
 | 
					
						
							|  |  |  |   heroImageUrl = 'images/hero.png'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   //iconUrl = 'https://angular.io/resources/images/logos/standard/shield-large.png';
 | 
					
						
							|  |  |  |   iconUrl = 'images/ng-logo.png'; | 
					
						
							|  |  |  |   isActive = false; | 
					
						
							|  |  |  |   isSpecial = true; | 
					
						
							|  |  |  |   isUnchanged = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   nullHero:Hero = null; // or undefined
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   onCancel(event:KeyboardEvent){ | 
					
						
							|  |  |  |     let evtMsg = event ? ' Event target is '+ (<HTMLElement>event.target).innerHTML : ''; | 
					
						
							|  |  |  |     this.alert('Canceled.'+evtMsg) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   onClickMe(event:KeyboardEvent){ | 
					
						
							|  |  |  |     let evtMsg = event ? ' Event target class is '+ (<HTMLElement>event.target).className  : ''; | 
					
						
							|  |  |  |     this.alert('Click me.'+evtMsg) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   onSave(event:KeyboardEvent){ | 
					
						
							|  |  |  |     let evtMsg = event ? ' Event target is '+ (<HTMLElement>event.target).innerText : ''; | 
					
						
							|  |  |  |     this.alert('Saved.'+evtMsg) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   onSubmit(form:NgForm){ | 
					
						
							|  |  |  |     let evtMsg = form.valid ? | 
					
						
							|  |  |  |       ' Form value is '+ JSON.stringify(form.value) : | 
					
						
							|  |  |  |       ' Form is invalid'; | 
					
						
							|  |  |  |     this.alert('Form submitted.'+evtMsg) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   product = { | 
					
						
							|  |  |  |     name: 'frimfram', | 
					
						
							|  |  |  |     price: 42 | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-06 17:18:26 -08:00
										 |  |  |   // #docregion refresh-heroes
 | 
					
						
							|  |  |  |   // update this.heroes with fresh set of cloned heroes
 | 
					
						
							|  |  |  |   refreshHeroes() { | 
					
						
							|  |  |  |     this.heroes = Hero.MockHeroes.map(hero => Hero.clone(hero)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   // #enddocregion refresh-heroes
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // #docregion same-as-it-ever-was
 | 
					
						
							| 
									
										
										
										
											2016-05-03 14:06:32 +02:00
										 |  |  |   private samenessCount = 5; | 
					
						
							|  |  |  |   moreOfTheSame() {this.samenessCount++;}; | 
					
						
							| 
									
										
										
										
											2016-02-06 17:18:26 -08:00
										 |  |  |   get sameAsItEverWas() { | 
					
						
							| 
									
										
										
										
											2016-05-03 14:06:32 +02:00
										 |  |  |     var result:string[] = Array(this.samenessCount); | 
					
						
							| 
									
										
										
										
											2016-02-06 17:18:26 -08:00
										 |  |  |     for (var i=result.length; i-- > 0;){result[i]='same as it ever was ...'} | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  |     // return [1,2,3,4,5].map(id => {
 | 
					
						
							|  |  |  |     //   return {id:id, text: 'same as it ever was ...'};
 | 
					
						
							|  |  |  |     // });
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   // #enddocregion same-as-it-ever-was
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-07 13:31:26 -08:00
										 |  |  |   setUpperCaseFirstName(firstName:string){ | 
					
						
							|  |  |  |     //console.log(firstName);
 | 
					
						
							|  |  |  |     this.currentHero.firstName = firstName.toUpperCase(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // #docregion setClasses
 | 
					
						
							|  |  |  |   setClasses() { | 
					
						
							| 
									
										
										
										
											2016-01-10 17:07:19 -08:00
										 |  |  |     let classes =  { | 
					
						
							| 
									
										
										
										
											2015-12-07 13:31:26 -08:00
										 |  |  |       saveable: this.canSave,      // true
 | 
					
						
							|  |  |  |       modified: !this.isUnchanged, // false
 | 
					
						
							|  |  |  |       special: this.isSpecial,     // true
 | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-01-10 17:07:19 -08:00
										 |  |  |     // #enddocregion setClasses
 | 
					
						
							|  |  |  |     // compensate for DevMode (sigh)
 | 
					
						
							| 
									
										
										
										
											2016-05-03 14:06:32 +02:00
										 |  |  |     if (JSON.stringify(classes) === JSON.stringify(this.priorClasses)){ | 
					
						
							|  |  |  |        return this.priorClasses; | 
					
						
							| 
									
										
										
										
											2016-01-10 17:07:19 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-05-03 14:06:32 +02:00
										 |  |  |     this.priorClasses = classes; | 
					
						
							| 
									
										
										
										
											2016-01-10 17:07:19 -08:00
										 |  |  |     // #docregion setClasses
 | 
					
						
							|  |  |  |     return classes; | 
					
						
							| 
									
										
										
										
											2015-12-07 13:31:26 -08:00
										 |  |  |   } | 
					
						
							|  |  |  |   // #enddocregion setClasses
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-10 17:07:19 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-07 13:31:26 -08:00
										 |  |  |   // #docregion setStyles
 | 
					
						
							|  |  |  |   setStyles() { | 
					
						
							| 
									
										
										
										
											2016-01-10 17:07:19 -08:00
										 |  |  |     let styles = { | 
					
						
							| 
									
										
										
										
											2015-12-13 22:29:37 -08:00
										 |  |  |       // CSS property names
 | 
					
						
							| 
									
										
										
										
											2015-12-07 13:31:26 -08:00
										 |  |  |       'font-style':  this.canSave      ? 'italic' : 'normal',  // italic
 | 
					
						
							|  |  |  |       'font-weight': !this.isUnchanged ? 'bold'   : 'normal',  // normal
 | 
					
						
							| 
									
										
										
										
											2016-01-28 16:01:39 -08:00
										 |  |  |       'font-size':   this.isSpecial    ? '24px'   : '8px',     // 24px
 | 
					
						
							| 
									
										
										
										
											2015-12-07 13:31:26 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-01-10 17:07:19 -08:00
										 |  |  |     // #enddocregion setStyles
 | 
					
						
							|  |  |  |     // compensate for DevMode (sigh)
 | 
					
						
							|  |  |  |     if (JSON.stringify(styles) === JSON.stringify(this._priorStyles)){ | 
					
						
							|  |  |  |        return this._priorStyles; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this._priorStyles = styles; | 
					
						
							|  |  |  |     // #docregion setStyles
 | 
					
						
							|  |  |  |     return styles; | 
					
						
							| 
									
										
										
										
											2015-12-07 13:31:26 -08:00
										 |  |  |   } | 
					
						
							|  |  |  |   // #enddocregion setStyles
 | 
					
						
							| 
									
										
										
										
											2016-01-10 17:07:19 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 22:29:37 -08:00
										 |  |  |   toeChoice = ''; | 
					
						
							|  |  |  |   toeChooser(picker:HTMLFieldSetElement){ | 
					
						
							| 
									
										
										
										
											2015-12-07 13:31:26 -08:00
										 |  |  |     let choices = picker.children; | 
					
						
							|  |  |  |     for (let i=0; i<choices.length; i++){ | 
					
						
							|  |  |  |       var choice = <HTMLInputElement>choices[i]; | 
					
						
							| 
									
										
										
										
											2015-12-13 22:29:37 -08:00
										 |  |  |       if (choice.checked) {return this.toeChoice = choice.value} | 
					
						
							| 
									
										
										
										
											2015-12-07 13:31:26 -08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-06 17:18:26 -08:00
										 |  |  |   title = 'Template Syntax'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // #docregion trackByHeroes
 | 
					
						
							|  |  |  |   trackByHeroes(index: number, hero: Hero) { return hero.id; } | 
					
						
							|  |  |  |   // #enddocregion trackByHeroes
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // #docregion trackById
 | 
					
						
							|  |  |  |   trackById(index: number, item: any): string { return item['id']; } | 
					
						
							|  |  |  |   // #enddocregion trackById
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-07 13:31:26 -08:00
										 |  |  |   val=2; | 
					
						
							|  |  |  |   //  villainImageUrl = 'http://www.clker.com/cliparts/u/s/y/L/x/9/villain-man-hi.png'
 | 
					
						
							|  |  |  |   // Public Domain terms of use http://www.clker.com/disclaimer.html
 | 
					
						
							|  |  |  |   villainImageUrl = 'images/villain.png' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-06 17:18:26 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   //////// Detect effects of NgForTrackBy ///////////////
 | 
					
						
							|  |  |  |   @ViewChildren('noTrackBy') childrenNoTrackBy:QueryList<ElementRef>; | 
					
						
							|  |  |  |   @ViewChildren('withTrackBy') childrenWithTrackBy:QueryList<ElementRef>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private _oldNoTrackBy:HTMLElement[]; | 
					
						
							|  |  |  |   private _oldWithTrackBy:HTMLElement[]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   heroesNoTrackByChangeCount = 0; | 
					
						
							|  |  |  |   heroesWithTrackByChangeCount = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 14:06:32 +02:00
										 |  |  |   private detectNgForTrackByEffects() { | 
					
						
							| 
									
										
										
										
											2016-02-06 17:18:26 -08:00
										 |  |  |     this._oldNoTrackBy   = toArray(this.childrenNoTrackBy); | 
					
						
							|  |  |  |     this._oldWithTrackBy = toArray(this.childrenWithTrackBy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this.childrenNoTrackBy.changes.subscribe((changes:any) => { | 
					
						
							|  |  |  |       let newNoTrackBy = toArray(changes); | 
					
						
							|  |  |  |       let isSame = this._oldNoTrackBy.every((v:any, i:number) => v === newNoTrackBy[i]); | 
					
						
							|  |  |  |       if (!isSame) { | 
					
						
							|  |  |  |         this._oldNoTrackBy = newNoTrackBy; | 
					
						
							|  |  |  |         this.heroesNoTrackByChangeCount++; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this.childrenWithTrackBy.changes.subscribe((changes:any) => { | 
					
						
							|  |  |  |       let newWithTrackBy = toArray(changes); | 
					
						
							|  |  |  |       let isSame = this._oldWithTrackBy.every((v:any, i:number) => v === newWithTrackBy[i]); | 
					
						
							|  |  |  |       if (!isSame) { | 
					
						
							|  |  |  |         this._oldWithTrackBy = newWithTrackBy; | 
					
						
							|  |  |  |         this.heroesWithTrackByChangeCount++; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   ///////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-07 13:31:26 -08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-02-06 17:18:26 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // helper to convert viewChildren to an array of HTMLElements
 | 
					
						
							|  |  |  | function toArray(viewChildren:QueryList<ElementRef>) { | 
					
						
							|  |  |  |   let result: HTMLElement[] = []; | 
					
						
							|  |  |  |   let children = viewChildren.toArray()[0].nativeElement.children; | 
					
						
							|  |  |  |   for (var i = 0; i < children.length; i++) { result.push(children[i]); } | 
					
						
							|  |  |  |   return result; | 
					
						
							| 
									
										
										
										
											2016-05-03 14:06:32 +02:00
										 |  |  | } |