parent
b7897eef85
commit
c33ee37144
|
@ -11,11 +11,11 @@
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"angular2": "2.0.0-alpha.46",
|
"angular2": "2.0.0-alpha.48",
|
||||||
"systemjs": "0.19.2"
|
"systemjs": "0.19.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"live-server": "^0.8.1",
|
"live-server": "^0.8.1",
|
||||||
"typescript": "^1.6.2"
|
"typescript": "^1.7.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,658 @@
|
||||||
|
<!-- #docregion my-first-app -->
|
||||||
|
<h3>My First Angular Application</h3>
|
||||||
|
<!-- #enddocregion my-first-app -->
|
||||||
|
|
||||||
|
<!-- Interpolation and expressions -->
|
||||||
|
<hr><h2>Interpolation</h2>
|
||||||
|
|
||||||
|
<!-- #docregion first-interpolation -->
|
||||||
|
<p>My current hero is {{currentHero.firstName}}</p>
|
||||||
|
<!-- #enddocregion first-interpolation -->
|
||||||
|
|
||||||
|
<!-- #docregion title+image -->
|
||||||
|
<h3>
|
||||||
|
{{title}}
|
||||||
|
<img src="{{heroImageUrl}}" style="height:30px">
|
||||||
|
</h3>
|
||||||
|
<!-- #enddocregion title+image -->
|
||||||
|
|
||||||
|
<!-- #docregion sum-1 -->
|
||||||
|
<!-- "The sum of 1 + 1 is 2" -->
|
||||||
|
<p>The sum of 1 + 1 is {{1 + 1}}</p>
|
||||||
|
<!-- #enddocregion sum-1 -->
|
||||||
|
|
||||||
|
<!-- #docregion sum-2 -->
|
||||||
|
<!-- "The sum of 1 + 1 is not 4" -->
|
||||||
|
<p>The sum of 1 + 1 is not {{1+1+getVal()}}</p>
|
||||||
|
<!-- #enddocregion sum-2 -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- New Mental Model -->
|
||||||
|
<hr><h2>New Mental Model</h2>
|
||||||
|
|
||||||
|
<!--<img src="http://www.wpclipart.com/cartoon/people/hero/hero_silhoutte_T.png">-->
|
||||||
|
<!-- Public Domain terms of use: http://www.wpclipart.com/terms.html -->
|
||||||
|
<!-- #docregion img+button -->
|
||||||
|
<div class="special">Mental Model</div>
|
||||||
|
<div><b>{{currentHero.fullName}}</b></div>
|
||||||
|
<img src="images/hero.png">
|
||||||
|
<button disabled>Save</button>
|
||||||
|
<!-- #enddocregion img+button -->
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!-- #docregion hero-detail-1 -->
|
||||||
|
<div class="special">Mental Model</div>
|
||||||
|
<hero-detail></hero-detail>
|
||||||
|
<!-- #enddocregion hero-detail-1 -->
|
||||||
|
</div>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!-- #docregion disabled-button-1 -->
|
||||||
|
<!-- Bind button disabled state to `isUnchanged` property -->
|
||||||
|
<button [disabled]="isUnchanged">Save</button>
|
||||||
|
<!-- #enddocregion disabled-button-1 -->
|
||||||
|
</div>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!-- #docregion property-binding-syntax-1 -->
|
||||||
|
<img [src] = "heroImageUrl">
|
||||||
|
<hero-detail [hero]="currentHero"></hero-detail>
|
||||||
|
<div [ng-class] = "{selected: isSelected}"></div>
|
||||||
|
<!-- #enddocregion property-binding-syntax-1 -->
|
||||||
|
</div>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<!-- #docregion event-binding-syntax-1 -->
|
||||||
|
<button (click) = "onSave()">Save</button>
|
||||||
|
<hero-detail (deleted)="onHeroDeleted()"></hero-detail>
|
||||||
|
<div my-click (my-click)="clicked=$event">click me</div>
|
||||||
|
<!-- #enddocregion event-binding-syntax-1 -->
|
||||||
|
{{clicked}}
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!-- #docregion 2-way-binding-syntax-1 -->
|
||||||
|
<input [(ng-model)]="heroName">
|
||||||
|
<!-- #enddocregion 2-way-binding-syntax-1 -->
|
||||||
|
Hero Name: {{heroName}}
|
||||||
|
</div>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<!-- #docregion attribute-binding-syntax-1 -->
|
||||||
|
<button [attr.aria-label]="help">help</button>
|
||||||
|
<!-- #enddocregion attribute-binding-syntax-1 -->
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<!-- #docregion class-binding-syntax-1 -->
|
||||||
|
<div [class.special]="isSpecial">Special</div>
|
||||||
|
<!-- #enddocregion class-binding-syntax-1 -->
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<!-- #docregion style-binding-syntax-1 -->
|
||||||
|
<button [style.color] = "isSpecial ? 'red' : 'green'">
|
||||||
|
<!-- #enddocregion style-binding-syntax-1 -->
|
||||||
|
button</button>
|
||||||
|
|
||||||
|
<hr><h2>kebab-case</h2>
|
||||||
|
<!-- #docregion bad-mixed-case -->
|
||||||
|
<!-- BAD: mixed case target names don't work
|
||||||
|
<label [textContent] = "title"></label>
|
||||||
|
<hero-detail [isActive] = "isActive"></hero-detail>
|
||||||
|
-->
|
||||||
|
<!-- #enddocregion bad-mixed-case -->
|
||||||
|
|
||||||
|
<!-- #docregion kebab-case -->
|
||||||
|
<!-- lower kebab-case -->
|
||||||
|
<label [text-content] = "title"></label>
|
||||||
|
<hero-detail [is-active] = "isActive"></hero-detail>
|
||||||
|
<!-- #enddocregion kebab-case -->
|
||||||
|
|
||||||
|
<!-- property vs. attribute -->
|
||||||
|
<hr><h2>Property vs. Attribute (img examples)</h2>
|
||||||
|
<!-- examine the following <img> tag in the browser tools -->
|
||||||
|
<img src="images/ng-logo.png"
|
||||||
|
[src]="heroImageUrl">
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<img [src]="iconUrl"/>
|
||||||
|
<img bind-src="heroImageUrl"/>
|
||||||
|
<img [attr.src]="villainImageUrl"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- buttons -->
|
||||||
|
<hr><h2>Buttons</h2>
|
||||||
|
|
||||||
|
<button>Enabled (but does nothing)</button>
|
||||||
|
<button disabled>Disabled</button>
|
||||||
|
<button disabled=false>Still disabled</button>
|
||||||
|
<br><br>
|
||||||
|
<button disabled>disabled by attribute</button>
|
||||||
|
<button [disabled]="isUnchanged">disabled by property binding</button>
|
||||||
|
<br><br>
|
||||||
|
<button bind-disabled="isUnchanged" on-click="onSave($event)">Disabled Cancel</button>
|
||||||
|
<button [disabled]="!canSave" (click)="onSave($event)">Enabled Save</button>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- property binding -->
|
||||||
|
<hr><h2>Property Binding</h2>
|
||||||
|
|
||||||
|
<!-- #docregion property-binding-1 -->
|
||||||
|
<img [src]="heroImageUrl">
|
||||||
|
<!-- #enddocregion property-binding-1 -->
|
||||||
|
<!-- #docregion property-binding-2 -->
|
||||||
|
<button [disabled]="isUnchanged">Cancel</button>
|
||||||
|
<!-- #enddocregion property-binding-2 -->
|
||||||
|
<!-- #docregion property-binding-3 -->
|
||||||
|
<div [ng-class]="'special'">NgClass is special</div>
|
||||||
|
<!-- #enddocregion property-binding-3 -->
|
||||||
|
<!-- #docregion property-binding-4 -->
|
||||||
|
<hero-detail [hero]="selectedHero"></hero-detail>
|
||||||
|
<!-- #enddocregion property-binding-4 -->
|
||||||
|
<!-- #docregion property-binding-5 -->
|
||||||
|
<img bind-src="heroImageUrl">
|
||||||
|
<!-- #enddocregion property-binding-5 -->
|
||||||
|
|
||||||
|
<!-- #docregion property-binding-6 -->
|
||||||
|
<!-- Doesn't work! HeroDetailComponent expects a Hero, not a string -->
|
||||||
|
<hero-detail hero="…what do we do here??? …"></hero-detail>
|
||||||
|
<!-- #enddocregion property-binding-6 -->
|
||||||
|
|
||||||
|
<!-- #docregion property-binding-v-interpolation -->
|
||||||
|
<img src="{{heroImageUrl}}">
|
||||||
|
<img [src]="'' + heroImageUrl">
|
||||||
|
|
||||||
|
<div>The title is {{title}}</div>
|
||||||
|
<div [text-content]="'The title is '+title"></div>
|
||||||
|
<!-- #enddocregion property-binding-v-interpolation -->
|
||||||
|
|
||||||
|
<!-- attribute binding -->
|
||||||
|
<hr><h2>Attribute Binding</h2>
|
||||||
|
|
||||||
|
<!-- create and set a colspan attribute -->
|
||||||
|
<!-- #docregion attrib-binding-colspan -->
|
||||||
|
<table border=1>
|
||||||
|
<!-- expression calculates colspan=2 -->
|
||||||
|
<tr><td [attr.colspan]="1 + 1">One-Two</td></tr>
|
||||||
|
|
||||||
|
<!-- ERROR: There is no `colspan` property to set!
|
||||||
|
<tr><td colspan="{{1+1}}">Three-Four</td></tr>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<tr><td>Five</td><td>Six</td></tr>
|
||||||
|
</table>
|
||||||
|
<!-- #enddocregion attrib-binding-colspan -->
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<!-- #docregion attrib-binding-aria -->
|
||||||
|
<!-- create and set an aria attribute for assistive technology -->
|
||||||
|
<button [attr.aria-label]="actionName">{{actionName}} with Aria</button>
|
||||||
|
<!-- #enddocregion attrib-binding-aria -->
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<!-- The following effects are not discussed in the chapter -->
|
||||||
|
<div>
|
||||||
|
<!-- any use of [attr.disabled] creates the disabled attribute -->
|
||||||
|
<button [attr.disabled]="isUnchanged">Disabled</button>
|
||||||
|
|
||||||
|
<button [attr.disabled]="!isUnchanged">Disabled as well</button>
|
||||||
|
|
||||||
|
<!-- can't remove it with [attr.disabled] either -->
|
||||||
|
<button disabled [attr.disabled]>Still disabled</button>
|
||||||
|
|
||||||
|
<!-- we'd have to remove it with property binding -->
|
||||||
|
<button disabled [disabled]="false">Enabled (but inert)</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- class binding -->
|
||||||
|
<hr><h2>Class Binding</h2>
|
||||||
|
|
||||||
|
<!-- #docregion class-binding-1 -->
|
||||||
|
<!-- standard class attribute setting -->
|
||||||
|
<div class="bad curly special">Bad curly special</div>
|
||||||
|
<!-- #enddocregion class-binding-1 -->
|
||||||
|
|
||||||
|
<!-- #docregion class-binding-2 -->
|
||||||
|
<!-- reset all class names with a string binding -->
|
||||||
|
<div class="bad curly special"
|
||||||
|
[class]="'bad curly'">Bad curly</div>
|
||||||
|
<!-- #enddocregion class-binding-2 -->
|
||||||
|
|
||||||
|
<!-- #docregion class-binding-3 -->
|
||||||
|
<!-- #docregion class-binding-3a -->
|
||||||
|
<!-- toggle the "special" class on/off with a property -->
|
||||||
|
<div [class.special]="isSpecial">The class binding is special</div>
|
||||||
|
<!-- #enddocregion class-binding-3a -->
|
||||||
|
|
||||||
|
<!-- binding to `class.special` trumps the class attribute -->
|
||||||
|
<div class="special"
|
||||||
|
[class.special]="!isSpecial">This one is not so special</div>
|
||||||
|
<!-- #enddocregion class-binding-3 -->
|
||||||
|
|
||||||
|
<div bind-class.special="isSpecial">This class binding is special too</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--style binding -->
|
||||||
|
<hr><h2>Style Binding</h2>
|
||||||
|
|
||||||
|
<!-- #docregion style-binding-1 -->
|
||||||
|
<button [style.color] = "isSpecial ? 'red' : 'green'">Red</button>
|
||||||
|
<button [style.background-color]="canSave ?'cyan' : 'grey'" >Save</button>
|
||||||
|
<!-- #enddocregion style-binding-1 -->
|
||||||
|
|
||||||
|
<!-- #docregion style-binding-2 -->
|
||||||
|
<button [style.font-size.em]="isSpecial ? 3 : 1" >Big</button>
|
||||||
|
<button [style.font-size.%]="!isSpecial ? 150 : 50" >Small</button>
|
||||||
|
<!-- #enddocregion style-binding-2 -->
|
||||||
|
|
||||||
|
<!-- event binding -->
|
||||||
|
<hr><h2>Event Binding</h2>
|
||||||
|
|
||||||
|
<!-- #docregion event-binding-1 -->
|
||||||
|
<button (click)="onSave()">Save</button>
|
||||||
|
<!-- #enddocregion event-binding-1 -->
|
||||||
|
|
||||||
|
<!-- #docregion event-binding-2 -->
|
||||||
|
<button on-click="onSave()">On Save</button>
|
||||||
|
<!-- #enddocregion event-binding-2 -->
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!-- #docregion event-binding-3 -->
|
||||||
|
<!-- `my-click` is an event on the custom `MyClickDirective` -->
|
||||||
|
<div my-click (my-click)="clickity=$event">click with my-click</div>
|
||||||
|
<!-- #enddocregion event-binding-3 -->
|
||||||
|
{{clickity}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- binding to a nested component -->
|
||||||
|
<!-- #docregion event-binding-to-component -->
|
||||||
|
<hero-detail (deleted)="onHeroDeleted($event)" [hero]="currentHero">
|
||||||
|
</hero-detail>
|
||||||
|
<!-- #enddocregion event-binding-to-component -->
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<big-hero-detail
|
||||||
|
(deleted)="onHeroDeleted($event)"
|
||||||
|
[hero]="currentHero">
|
||||||
|
</big-hero-detail>
|
||||||
|
|
||||||
|
<!-- #docregion event-binding-bubbling -->
|
||||||
|
<div class="parent-div" (click)="onClickMe($event)">Click me
|
||||||
|
<div class="child-div">Click me too!</div>
|
||||||
|
</div>
|
||||||
|
<!-- #enddocregion event-binding-bubbling -->
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<!-- #docregion event-binding-no-propagation -->
|
||||||
|
<!-- Will save only once -->
|
||||||
|
<div (click)="onSave()">
|
||||||
|
<button (click)="onSave()">Save, no propagation</button>
|
||||||
|
</div>
|
||||||
|
<!-- #enddocregion event-binding-no-propagation -->
|
||||||
|
<br><br>
|
||||||
|
<!-- #docregion event-binding-propagation -->
|
||||||
|
<!-- Will save twice -->
|
||||||
|
<div (click)="onSave()">
|
||||||
|
<button (click)="onSave() || true">Save w/ propagation</button>
|
||||||
|
</div>
|
||||||
|
<!-- #enddocregion event-binding-propagation -->
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Two way data binding unwound;
|
||||||
|
passing the changed display value to the event handler via `$event` -->
|
||||||
|
<hr><h2>NgModel Binding</h2>
|
||||||
|
|
||||||
|
<h3>Result: {{currentHero.firstName}}</h3>
|
||||||
|
|
||||||
|
<!-- #docregion without-NgModel -->
|
||||||
|
<input [value]="currentHero.firstName"
|
||||||
|
(input)="currentHero.firstName=$event.target.value" >
|
||||||
|
<!-- #enddocregion without-NgModel -->
|
||||||
|
without NgModel
|
||||||
|
<br>
|
||||||
|
<!-- #docregion NgModel-1 -->
|
||||||
|
<input [(ng-model)]="currentHero.firstName">
|
||||||
|
<!-- #enddocregion NgModel-1 -->
|
||||||
|
[(ng-model)]
|
||||||
|
<br>
|
||||||
|
<!-- #docregion NgModel-2 -->
|
||||||
|
<input bindon-ng-model="currentHero.firstName">
|
||||||
|
<!-- #enddocregion NgModel-2 -->
|
||||||
|
bindon-ng-model
|
||||||
|
<br>
|
||||||
|
<!-- #docregion NgModel-3 -->
|
||||||
|
<input
|
||||||
|
[ng-model]="currentHero.firstName"
|
||||||
|
(ng-model-change)="currentHero.firstName=$event">
|
||||||
|
<!-- #enddocregion NgModel-3 -->
|
||||||
|
(ng-model-change) = "...firstName=$event"
|
||||||
|
<br>
|
||||||
|
<!-- #docregion NgModel-4 -->
|
||||||
|
<input
|
||||||
|
[ng-model]="currentHero.firstName"
|
||||||
|
(ng-model-change)="setUpperCaseFirstName($event)">
|
||||||
|
<!-- #enddocregion NgModel-4 -->
|
||||||
|
(ng-model-change) = "setUpperCaseFirstName($event)"
|
||||||
|
<br>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- NgClass binding -->
|
||||||
|
<hr><h2>NgClass Binding</h2>
|
||||||
|
|
||||||
|
<p>setClasses returns {{setClasses() | json}}</p>
|
||||||
|
<!-- #docregion NgClass-1 -->
|
||||||
|
<div [ng-class]="setClasses()">This div is saveable and special</div>
|
||||||
|
<!-- #enddocregion NgClass-1 -->
|
||||||
|
<div [ng-class]="setClasses()" #class-div>
|
||||||
|
After setClasses(), the classes are "{{classDiv.className}}"
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- not used in chapter -->
|
||||||
|
|
||||||
|
<div [ng-class]="isSpecial ? 'special' : ''">This div is special</div>
|
||||||
|
|
||||||
|
<div class="bad curly special">Bad curly special</div>
|
||||||
|
<div [ng-class]="{bad:false, curly:true, special:true}">Curly special</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- NgStyle binding -->
|
||||||
|
<hr><h2>NgStyle Binding</h2>
|
||||||
|
|
||||||
|
<!-- #docregion NgStyle-1 -->
|
||||||
|
<div [style.font-size]="isSpecial ? 'x-large' : 'smaller'" >
|
||||||
|
This div is x-large
|
||||||
|
</div>
|
||||||
|
<!-- #enddocregion NgStyle-1 -->
|
||||||
|
|
||||||
|
<p>setStyles returns {{setStyles() | json}}</p>
|
||||||
|
<!-- #docregion NgStyle-2 -->
|
||||||
|
<div [ng-style]="setStyles()">
|
||||||
|
This div is italic, normal weight, and x-large
|
||||||
|
</div>
|
||||||
|
<!-- #enddocregion NgStyle-2 -->
|
||||||
|
<div [ng-style]="setStyles()" #style-div>
|
||||||
|
After setStyles(), the styles are "{{getStyles(styleDiv)}}"
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- not used in chapter -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- NgIf binding -->
|
||||||
|
<hr><h2>NgIf Binding</h2>
|
||||||
|
|
||||||
|
<!-- #docregion NgIf-1 -->
|
||||||
|
<div *ng-if="currentHero">Hello, {{currentHero.firstName}}</div>
|
||||||
|
<!-- #enddocregion NgIf-1 -->
|
||||||
|
|
||||||
|
<!-- #docregion NgIf-2 -->
|
||||||
|
<!-- not displayed because nullHero is falsey.
|
||||||
|
`nullHero.firstName` never has a chance to fail -->
|
||||||
|
<div *ng-if="nullHero">Hello, {{nullHero.firstName}}</div>
|
||||||
|
|
||||||
|
<!-- Hero Detail is not in the DOM because isActive is false-->
|
||||||
|
<hero-detail *ng-if="isActive"></hero-detail>
|
||||||
|
<!-- #enddocregion NgIf-2 -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- NgIf binding with template (no *) -->
|
||||||
|
|
||||||
|
<template [ng-if]="currentHero">Add {{currentHero.firstName}} with template</template>
|
||||||
|
|
||||||
|
<!-- Does not show because isActive is false! -->
|
||||||
|
<div>Hero Detail removed from DOM (via template) because isActive is false</div>
|
||||||
|
<template [ng-if]="isActive">
|
||||||
|
<hero-detail></hero-detail>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- #docregion NgIf-3 -->
|
||||||
|
<!-- isSpecial is true -->
|
||||||
|
<div [class.hidden]="!isSpecial">Show with class</div>
|
||||||
|
<div [class.hidden]="isSpecial">Hide with class</div>
|
||||||
|
|
||||||
|
<!-- HeroDetail is in the DOM but hidden -->
|
||||||
|
<hero-detail [class.hidden]="isSpecial"></hero-detail>
|
||||||
|
|
||||||
|
<div [style.display]="isSpecial ? 'block' : 'none'">Show with style</div>
|
||||||
|
<div [style.display]="isSpecial ? 'none' : 'block'">Hide with style</div>
|
||||||
|
<!-- #enddocregion NgIf-3 -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- NgSwitch binding -->
|
||||||
|
<hr><h2>NgSwitch Binding</h2>
|
||||||
|
|
||||||
|
<fieldset #toe-picker (click)="null" >
|
||||||
|
<input type="radio" name="toes" value="Eenie">Eenie
|
||||||
|
<input type="radio" name="toes" checked value="Meanie">Meanie
|
||||||
|
<input type="radio" name="toes" value="Miney">Miney
|
||||||
|
<input type="radio" name="toes" value="Moe">Moe
|
||||||
|
<input type="radio" name="toes" value="???">???
|
||||||
|
</fieldset>
|
||||||
|
<!-- #docregion NgSwitch -->
|
||||||
|
<div class="toe">You picked
|
||||||
|
<span [ng-switch]="toeChoice(toePicker)">
|
||||||
|
<template [ng-switch-when]="'Eenie'">Eenie</template>
|
||||||
|
<template [ng-switch-when]="'Meanie'">Meanie</template>
|
||||||
|
<template [ng-switch-when]="'Miney'">Miney</template>
|
||||||
|
<template [ng-switch-when]="'Moe'">Moe</template>
|
||||||
|
<template ng-switch-default>Other</template>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<!-- #enddocregion NgSwitch -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- NgFor binding -->
|
||||||
|
<hr><h2>NgFor Binding</h2>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<!-- #docregion NgFor-1 -->
|
||||||
|
<div *ng-for="#hero of heroes">{{hero.fullName}}</div>
|
||||||
|
<!-- #enddocregion NgFor-1 -->
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<!-- *ng-for w/ hero-detail Component -->
|
||||||
|
<!-- #docregion NgFor-2 -->
|
||||||
|
<hero-detail *ng-for="#hero of heroes" [hero]="hero"></hero-detail>
|
||||||
|
<!-- #enddocregion NgFor-2 -->
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<!-- Ex: 1 - Hercules Son of Zeus -->
|
||||||
|
<!-- #docregion NgFor-3 -->
|
||||||
|
<div *ng-for="#hero of heroes, #i=index">{{i+1}} - {{hero.fullName}}</div>
|
||||||
|
<!-- #enddocregion NgFor-3 -->
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<!-- * and template -->
|
||||||
|
<hr><h2>* and Template</h2>
|
||||||
|
|
||||||
|
<h3>NgIf expansion</h3>
|
||||||
|
<!-- #docregion Template-1 -->
|
||||||
|
<hero-detail *ng-if="currentHero" [hero]="currentHero"></hero-detail>
|
||||||
|
<!-- #enddocregion Template-1 -->
|
||||||
|
|
||||||
|
<!-- #docregion Template-2 -->
|
||||||
|
<template [ng-if]="currentHero">
|
||||||
|
<hero-detail [hero]="currentHero"></hero-detail>
|
||||||
|
</template>
|
||||||
|
<!-- #enddocregion Template-2 -->
|
||||||
|
|
||||||
|
<h3>NgFor expansion</h3>
|
||||||
|
<div class="box">
|
||||||
|
<!-- ng-for w/ hero-detail Component and a template "attribute" directive -->
|
||||||
|
<!-- #docregion Template-3 -->
|
||||||
|
<hero-detail template="ng-for #hero of heroes" [hero]="hero"></hero-detail>
|
||||||
|
<!-- #enddocregion Template-3 -->
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<!-- ng-for w/ hero-detail Component inside a template element -->
|
||||||
|
<!-- #docregion Template-4 -->
|
||||||
|
<template ng-for #hero [ng-for-of]="heroes">
|
||||||
|
<hero-detail [hero]="hero"></hero-detail>
|
||||||
|
</template>
|
||||||
|
<!-- #enddocregion Template-4 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- template local variable -->
|
||||||
|
<hr><h2>Template local variables</h2>
|
||||||
|
|
||||||
|
<!-- #docregion var-phone -->
|
||||||
|
<!-- phone refers to the input element; pass its `value` to an event handler -->
|
||||||
|
<input #phone placeholder="phone number">
|
||||||
|
<button (click)="callPhone(phone.value)">Call</button>
|
||||||
|
|
||||||
|
<!-- fax refers to the input element; pass its `value` to an event handler -->
|
||||||
|
<input var-fax placeholder="phone number">
|
||||||
|
<button (click)="callFax(fax.value)">Fax</button>
|
||||||
|
<!-- #enddocregion var-phone -->
|
||||||
|
|
||||||
|
<h4>Example Form</h4>
|
||||||
|
<!-- #docregion var-form -->
|
||||||
|
<!-- #docregion var-form-a -->
|
||||||
|
<form (ng-submit)="onSubmit(theForm)" #theForm="form">
|
||||||
|
<!-- #enddocregion var-form-a -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name">Name</label>
|
||||||
|
<input class="form-control" required ng-control="firstName"
|
||||||
|
[(ng-model)]="currentHero.firstName">
|
||||||
|
</div>
|
||||||
|
<!-- #docregion var-form-a -->
|
||||||
|
<button type="submit" [disabled]="!theForm.form.valid">Submit</button>
|
||||||
|
</form>
|
||||||
|
<!-- #enddocregion var-form-a -->
|
||||||
|
<!-- #enddocregion var-form -->
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<!-- btn refers to the button element; show its disabled state -->
|
||||||
|
<button #btn disabled [text-content]="'disabled by attribute: '+btn.disabled"></button>
|
||||||
|
|
||||||
|
<!-- inputs and output -->
|
||||||
|
<hr><h2>Inputs and Outputs</h2>
|
||||||
|
|
||||||
|
<!-- #docregion io-1 -->
|
||||||
|
<img [src]="iconUrl"/>
|
||||||
|
<button (click)="onSave()">Save</button>
|
||||||
|
<!-- #enddocregion io-1 -->
|
||||||
|
|
||||||
|
<!-- #docregion io-2 -->
|
||||||
|
<hero-detail [hero]="currentHero" (deleted)="onHeroDeleted($event)">
|
||||||
|
</hero-detail>
|
||||||
|
<!-- #enddocregion io-2 -->
|
||||||
|
|
||||||
|
<div my-click2 (my-click)="clicked2=$event">my-click2</div>
|
||||||
|
{{clicked2}}
|
||||||
|
|
||||||
|
<!-- Pipes -->
|
||||||
|
<hr><h2>Pipes</h2>
|
||||||
|
|
||||||
|
<!-- #docregion pipes-1 -->
|
||||||
|
<!-- Force title to uppercase -->
|
||||||
|
<div>{{ title | uppercase }}</div>
|
||||||
|
<!-- #enddocregion pipes-1 -->
|
||||||
|
|
||||||
|
<!-- #docregion pipes-2 -->
|
||||||
|
<!-- Pipe chaining: force title to uppercase, then to lowercase -->
|
||||||
|
<div>{{ title | uppercase | lowercase }}</div>
|
||||||
|
<!-- #enddocregion pipes-2 -->
|
||||||
|
|
||||||
|
<!-- #docregion pipes-3 -->
|
||||||
|
<!-- pipe with configuration argument => "February 25, 1970" -->
|
||||||
|
<div>Birthdate: {{currentHero?.birthdate | date:'longDate'}}</div>
|
||||||
|
<!-- #enddocregion pipes-3 -->
|
||||||
|
|
||||||
|
<!-- #docregion pipes-json -->
|
||||||
|
<div>{{currentHero | json}}</div>
|
||||||
|
|
||||||
|
<!-- Output:
|
||||||
|
{ "firstName": "Hercules", "lastName": "Son of Zeus",
|
||||||
|
"birthdate": "1970-02-25T08:00:00.000Z",
|
||||||
|
"url": "http://www.imdb.com/title/tt0065832/",
|
||||||
|
"rate": 325, "id": 1 }
|
||||||
|
-->
|
||||||
|
<!-- #enddocregion pipes-json -->
|
||||||
|
|
||||||
|
|
||||||
|
<div>Birthdate: {{(currentHero?.birthdate | date:'longDate') | uppercase}}</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!-- pipe price to USD and display the $ symbol -->
|
||||||
|
<label>Price: </label>{{product.price | currency:'USD':true}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Null values and the Elvis operator -->
|
||||||
|
<hr><h2>Elvis</h2>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!-- #docregion elvis-1 -->
|
||||||
|
The title is {{ title }}
|
||||||
|
<!-- #enddocregion elvis-1 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!-- #docregion elvis-2 -->
|
||||||
|
The current hero's name is {{currentHero?.firstName}}
|
||||||
|
<!-- #enddocregion elvis-2 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!-- #docregion elvis-3 -->
|
||||||
|
The current hero's name is {{currentHero.firstName}}
|
||||||
|
<!-- #enddocregion elvis-3 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
The null hero's name is {{nullHero.firstName}}
|
||||||
|
|
||||||
|
See console log
|
||||||
|
TypeError: Cannot read property 'firstName' of null in [null]
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- #docregion elvis-4 -->
|
||||||
|
<!--No hero, div not displayed, no error -->
|
||||||
|
<div *ng-if="nullHero">The null hero's name is {{nullHero.firstName}}</div>
|
||||||
|
<!-- #enddocregion elvis-4 -->
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!-- #docregion elvis-5 -->
|
||||||
|
The null hero's name is {{nullHero && nullHero.firstName}}
|
||||||
|
<!-- #enddocregion elvis-5 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!-- #docregion elvis-6 -->
|
||||||
|
<!-- No hero, no problem! -->
|
||||||
|
The null hero's name is {{nullHero?.firstName}}
|
||||||
|
<!-- #enddocregion elvis-6 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Todo: discuss this in the Style binding section -->
|
||||||
|
<!-- enums in bindings -->
|
||||||
|
<hr><h2>Enums in binding</h2>
|
||||||
|
|
||||||
|
<p>The name of the Color.Red enum is {{Color[Color.Red]}}</p>
|
||||||
|
<p>The current color number is {{color}}</p>
|
||||||
|
<p><button [style.color]="Color[color]" (click)="colorToggle()">Enum Toggle</button>
|
|
@ -0,0 +1,134 @@
|
||||||
|
import {Component, NgForm} from 'angular2/core';
|
||||||
|
|
||||||
|
import {Hero} from './hero';
|
||||||
|
import {HeroDetailComponent, BigHeroDetailComponent} from './hero-detail.component';
|
||||||
|
import {MyClickDirective, MyClickDirective2} from './my-click.directive';
|
||||||
|
|
||||||
|
// 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
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AppComponent {
|
||||||
|
|
||||||
|
actionName = 'Go for it';
|
||||||
|
alert = alerter;
|
||||||
|
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];
|
||||||
|
|
||||||
|
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};
|
||||||
|
|
||||||
|
heroes = Hero.MockHeroes;
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
onHeroDeleted(hero:Hero){
|
||||||
|
this.alert('Deleted hero: '+ (hero && hero.firstName))
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
setUpperCaseFirstName(firstName:string){
|
||||||
|
//console.log(firstName);
|
||||||
|
this.currentHero.firstName = firstName.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
// #docregion setClasses
|
||||||
|
setClasses() {
|
||||||
|
return {
|
||||||
|
saveable: this.canSave, // true
|
||||||
|
modified: !this.isUnchanged, // false
|
||||||
|
special: this.isSpecial, // true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #enddocregion setClasses
|
||||||
|
|
||||||
|
// #docregion setStyles
|
||||||
|
setStyles() {
|
||||||
|
return {
|
||||||
|
'font-style': this.canSave ? 'italic' : 'normal', // italic
|
||||||
|
'font-weight': !this.isUnchanged ? 'bold' : 'normal', // normal
|
||||||
|
'font-size': this.isSpecial ? 'x-large': 'smaller', // larger
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #enddocregion setStyles
|
||||||
|
|
||||||
|
toeChoice(picker:HTMLFieldSetElement){
|
||||||
|
let choices = picker.children;
|
||||||
|
for (let i=0; i<choices.length; i++){
|
||||||
|
var choice = <HTMLInputElement>choices[i];
|
||||||
|
if (choice.checked) {return choice.value}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
title = 'Template Syntax'
|
||||||
|
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'
|
||||||
|
|
||||||
|
}
|
|
@ -1,383 +0,0 @@
|
||||||
<!-- Interpolation and expressions</h1> -->
|
|
||||||
<h3>My First Angular Application</h3>
|
|
||||||
<h3>
|
|
||||||
{{title}}
|
|
||||||
<img src="{{heroImageUrl}}" style="height:30px">
|
|
||||||
</h3>
|
|
||||||
<p>My current hero is {{currentHero.firstName}}</p>
|
|
||||||
|
|
||||||
<div title="Hello {{currentHero.firstName}}">
|
|
||||||
Hey there, {{currentHero.firstName}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3 [text-content]="'The title is '+title"></h3>
|
|
||||||
<h3>The title is {{title}}</h3>
|
|
||||||
<h3>The sum of 1 + 1 is not {{1+1+getVal()}}</h3>
|
|
||||||
<h3 id="3" #f>The element id is {{f.id}}</h3>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<img src="{{heroImageUrl}}"/>
|
|
||||||
<img [src]="'' + heroImageUrl"/>
|
|
||||||
|
|
||||||
<h3>The title is {{title}}</h3>
|
|
||||||
<h3 [text-content]="'The title is '+title"></h3>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- New Mental Model -->
|
|
||||||
<hr>
|
|
||||||
<div class="special">Mental Model</div>
|
|
||||||
|
|
||||||
<div class="special">
|
|
||||||
<!--<img src="http://www.wpclipart.com/cartoon/people/hero/hero_silhoutte_T.png">-->
|
|
||||||
<img src="images/hero.png">
|
|
||||||
<button disabled>Save</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div *ng-if="false">
|
|
||||||
<hero-detail></hero-detail>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<!-- BAD: No Mixed Case
|
|
||||||
<h3 [textContent]="title"></h3>
|
|
||||||
-->
|
|
||||||
<!-- property over attribute -->
|
|
||||||
<!-- examine the following <img> tag in the browser tools -->
|
|
||||||
<img src="images/ng-logo.png"
|
|
||||||
[src]="heroImageUrl">
|
|
||||||
<hr>
|
|
||||||
<h3 [text-content]="title"></h3>
|
|
||||||
<hr/>
|
|
||||||
<img [src]="iconUrl"/>
|
|
||||||
<img bind-src="heroImageUrl"/>
|
|
||||||
<img [attr.src]="villainImageUrl"/>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- buttons -->
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<button>Enabled</button>
|
|
||||||
<button disabled>Disabled</button>
|
|
||||||
<button disabled=false>Still disabled</button>
|
|
||||||
<hr>
|
|
||||||
<button disabled>disabled by attribute</button>
|
|
||||||
<button [disabled]="isUnchanged">disabled by property binding</button>
|
|
||||||
|
|
||||||
<button bind-disabled="isUnchanged" on-click="onSave($event)">Disabled Cancel</button>
|
|
||||||
<button [disabled]="!canSave" (click)="onSave($event)">Enabled Save</button>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- event binding -->
|
|
||||||
|
|
||||||
<button (click)="onSave()">Save</button>
|
|
||||||
<button on-click="onSave()">On Save</button>
|
|
||||||
<button (click)="onSave() || true">Save w/ propagation</button>
|
|
||||||
|
|
||||||
<button (click)="onClickMe()">Click me!</button>
|
|
||||||
|
|
||||||
<div class="parent-div" (click)="onClickMe($event)">Click me
|
|
||||||
<div class="child-div">Click me too!</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<click-me></click-me>
|
|
||||||
|
|
||||||
<h4>keyup loop-back component</h4>
|
|
||||||
<loop-back></loop-back>
|
|
||||||
|
|
||||||
<key-up></key-up>
|
|
||||||
|
|
||||||
<key-up2></key-up2>
|
|
||||||
|
|
||||||
<key-up3></key-up3>
|
|
||||||
<br>
|
|
||||||
<div class="box">
|
|
||||||
<little-tour></little-tour>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- attribute binding -->
|
|
||||||
<hr>
|
|
||||||
<!-- any value creates the disabled attribute -->
|
|
||||||
<button [attr.disabled]="isUnchanged">Disabled</button>
|
|
||||||
<button [attr.disabled]="isUnchanged">Disabled as well</button>
|
|
||||||
|
|
||||||
<!-- lack of expression removes the attribute -->
|
|
||||||
<button disabled [attr.disabled]>Enabled</button>
|
|
||||||
|
|
||||||
<!-- create and set an aria attribute for assistive technology -->
|
|
||||||
<button [attr.aria-label]="actionName">{{actionName}} with Aria</button>
|
|
||||||
|
|
||||||
<!-- create and set a span attribute -->
|
|
||||||
<table border=1>
|
|
||||||
<tr><td>One</td><td>Two</td></tr>
|
|
||||||
|
|
||||||
<!-- ERROR: There is no `colspan` property to set!
|
|
||||||
<tr><td colspan="{{1+1}}">Three-Four</td></tr>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!-- expression calculates colspan=2 -->
|
|
||||||
<tr><td [attr.colspan]="1 + 1">Five-Six</td></tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- class binding -->
|
|
||||||
<hr>
|
|
||||||
<div class="special">The class is special</div>
|
|
||||||
<div [class]="'special'">The class is special</div>
|
|
||||||
<!-- toggle the "special" class on and ohf -->
|
|
||||||
<div [class.special]="isSpecial">The class binding is special</div>
|
|
||||||
|
|
||||||
<div class="special" [class.special]="!isSpecial">This one is not so special</div>
|
|
||||||
|
|
||||||
<div bind-class.special="isSpecial">This class binding is special too</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--style binding -->
|
|
||||||
<hr>
|
|
||||||
<button [style.color] = "isSpecial ? 'red' : 'green'">Red</button>
|
|
||||||
<button [style.background-color]="canSave ?'cyan' : 'grey'" >Save</button>
|
|
||||||
<button [style.font-size.em]="isSpecial ? 3 : 1" >Big</button>
|
|
||||||
<button [style.font-size.%]="!isSpecial ? 150 : 50" >Small</button>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- binding to a nested component -->
|
|
||||||
<hr>
|
|
||||||
<div>{{currentHero?.firstName}}</div>
|
|
||||||
|
|
||||||
<hero-detail [hero]="currentHero" (deleted)="onDeleted($event)"></hero-detail>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Two way data binding unwound;
|
|
||||||
passing the changed display value to the event handler via `$event` -->
|
|
||||||
<hr>
|
|
||||||
<input [value]="currentHero.firstName"
|
|
||||||
(input)="currentHero.firstName=$event.target.value" >
|
|
||||||
<br>
|
|
||||||
<input [(ng-model)]="currentHero.firstName">
|
|
||||||
<br>
|
|
||||||
<input
|
|
||||||
[ng-model]="currentHero.firstName"
|
|
||||||
(ng-model-change)="currentHero.firstName=$event">
|
|
||||||
<br>
|
|
||||||
<input
|
|
||||||
[ng-model]="currentHero.lastName"
|
|
||||||
(ng-model-change)="setLastName($event)">
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<div>{{currentHero.fullName}}</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- NgClass binding -->
|
|
||||||
<hr>
|
|
||||||
<div [ng-class]="isSpecial ? special : ''">This div is special</div>
|
|
||||||
|
|
||||||
<div [ng-class]="setClasses()">This div is saveable and special</div>
|
|
||||||
<div [ng-class]="setClasses()" #class-div>
|
|
||||||
After setClasses(), the classes are "{{classDiv.className}}"
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- NgStyle binding -->
|
|
||||||
<hr>
|
|
||||||
<div [style.font-size]="isSpecial ? 'larger' : 'smaller'" >This div is larger</div>
|
|
||||||
|
|
||||||
<div [ng-style]="setStyles()">This div is italic, normal weight, and larger</div>
|
|
||||||
<div [ng-style]="setStyles()" #class-div>
|
|
||||||
After setStyles(), the styles are "{{getStyles(classDiv)}}"
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- NgIf binding -->
|
|
||||||
<hr>
|
|
||||||
<div><b>NgIf Binding</b></div>
|
|
||||||
|
|
||||||
<div *ng-if="currentHero">Add {{currentHero.firstName}}</div>
|
|
||||||
<div *ng-if="nullHero">Remove {{nullHero.firstName}}</div>
|
|
||||||
|
|
||||||
<div>Hero Detail removed from DOM because isActive is false</div>
|
|
||||||
<hero-detail *ng-if="isActive" [hero]="currentHero"></hero-detail>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- NgIf binding with template (no *) -->
|
|
||||||
|
|
||||||
<template [ng-if]="currentHero">Add {{currentHero.firstName}} with template</template>
|
|
||||||
|
|
||||||
<!-- Does not show because isActive is false! -->
|
|
||||||
<div>Hero Detail removed from DOM (via template) because isActive is false</div>
|
|
||||||
<template [ng-if]="isActive">
|
|
||||||
<hero-detail [hero]="currentHero"></hero-detail>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- isSpecial is true -->
|
|
||||||
<div [class.hidden]="!isSpecial">Show with class</div>
|
|
||||||
<div [class.hidden]="isSpecial">Hide with class</div>
|
|
||||||
<hero-detail [class.hidden]="isSpecial" [hero]="currentHero"></hero-detail>
|
|
||||||
|
|
||||||
<div [style.display]="isSpecial ? 'block' : 'none'">Show with style</div>
|
|
||||||
<div [style.display]="isSpecial ? 'none' : 'block'">Hide with style</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- NgSwitch binding -->
|
|
||||||
<hr>
|
|
||||||
<div><b>NgSwitch Binding</b></div>
|
|
||||||
<fieldset #toe-picker (click)="null" >
|
|
||||||
<input type="radio" name="toes" value="Eenie">Eenie
|
|
||||||
<input type="radio" name="toes" checked value="Meanie">Meanie
|
|
||||||
<input type="radio" name="toes" value="Miney">Miney
|
|
||||||
<input type="radio" name="toes" value="Moe">Moe
|
|
||||||
<input type="radio" name="toes" value="???">???
|
|
||||||
</fieldset>
|
|
||||||
<div class="toe">You picked
|
|
||||||
<span [ng-switch]="toeChoice(toePicker)">
|
|
||||||
<template [ng-switch-when]="'Eenie'">Eenie</template>
|
|
||||||
<template [ng-switch-when]="'Meanie'">Meanie</template>
|
|
||||||
<template [ng-switch-when]="'Miney'">Miney</template>
|
|
||||||
<template [ng-switch-when]="'Moe'">Moe</template>
|
|
||||||
<template ng-switch-default>Other</template>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- NgFor binding -->
|
|
||||||
<hr>
|
|
||||||
<div><b>NgFor Binding</b></div>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<div class="box">
|
|
||||||
<!-- *ng-for of div w/ interpolation -->
|
|
||||||
<div *ng-for="#hero of heroes">{{hero.fullName}}</div>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<div class="box">
|
|
||||||
<!-- *ng-for of div w/ interpolation -->
|
|
||||||
<!-- Ex: 1 - Hercules Son of Zeus -->
|
|
||||||
<div *ng-for="#hero of heroes, #i=index">{{i+1}} - {{hero.fullName}}</div>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<div class="box">
|
|
||||||
<!-- *ng-for w/ little-hero Component -->
|
|
||||||
<little-hero *ng-for="#hero of heroes" [hero]="hero"></little-hero>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<div class="box">
|
|
||||||
<!-- ng-for w/ little-hero Component and a template "attribute" directive -->
|
|
||||||
<little-hero template="ng-for #hero of heroes" [hero]="hero"></little-hero>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<div class="box">
|
|
||||||
<!-- ng-for w/ little-hero Component inside a template element -->
|
|
||||||
<template ng-for #hero [ng-for-of]="heroes">
|
|
||||||
<little-hero [hero]="hero"></little-hero>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Pipe operator -->
|
|
||||||
<hr>
|
|
||||||
<!-- Force title to uppercase -->
|
|
||||||
<div>{{ title | uppercase }}</div>
|
|
||||||
|
|
||||||
<!-- Pipe chaining: force title to uppercase, then to lowercase -->
|
|
||||||
<div>{{ title | uppercase | lowercase }}</div>
|
|
||||||
|
|
||||||
<!-- pipe with configuration argument -->
|
|
||||||
<div>Birthdate: {{currentHero?.birthdate | date:'longDate'}}</div>
|
|
||||||
|
|
||||||
<div>Birthdate: {{(currentHero?.birthdate | date:'longDate') | uppercase}}</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<!-- pipe price to USD and display the $ symbol -->
|
|
||||||
<label>Price: </label>{{product.price | currency:'USD':true}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Null values and the Elvis operator -->
|
|
||||||
<hr>
|
|
||||||
<div>The title is {{ title }}</div>
|
|
||||||
|
|
||||||
<div>The current hero's name is {{currentHero?.firstName}}</div>
|
|
||||||
|
|
||||||
<div>The current hero's name is {{currentHero.firstName}}</div>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
<div>The null hero's name is {{nullHero.firstName}}</div>
|
|
||||||
|
|
||||||
See console log
|
|
||||||
TypeError: Cannot read property 'firstName' of null in [null]
|
|
||||||
-->
|
|
||||||
<!--No hero, div not displayed, no error -->
|
|
||||||
<div *ng-if="nullHero">The null hero's name is {{nullHero?.firstName}}</div>
|
|
||||||
|
|
||||||
<!--guard in the expression, no display, no error
|
|
||||||
[FAILS No short-circuiting of logical operators]
|
|
||||||
<div>The null hero's name is {{nullHero && nullHero.firstName}}</div>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!-- No hero, no problem! -->
|
|
||||||
<div>The null hero's name is {{nullHero?.firstName}}</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- template local variable -->
|
|
||||||
<hr>
|
|
||||||
<h3>Template Driven Form</h3>
|
|
||||||
<form (ng-submit)="onSubmit(hf)" #hf="form">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="name">Name</label>
|
|
||||||
<input type="text" class="form-control" required
|
|
||||||
ng-control="firstName"
|
|
||||||
[(ng-model)]="currentHero.firstName">
|
|
||||||
</div>
|
|
||||||
<button type="submit" [disabled]="!hf.form.valid">Submit</button>
|
|
||||||
</form>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- btn refers to the button element; show its disabled state -->
|
|
||||||
<button #btn disabled [text-content]="'disabled by attribute: '+btn.disabled"></button>
|
|
||||||
|
|
||||||
<!-- phone refers to the input element; pass its `value` to an event handler -->
|
|
||||||
<input #phone placeholder="phone number">
|
|
||||||
<button (click)="callPhone(phone.value)">Call</button>
|
|
||||||
|
|
||||||
<!-- ohficFax refers to the input element; pass its `value` to an event handler -->
|
|
||||||
<input var-ohfice-fax placeholder="phone number">
|
|
||||||
<button (click)="callFax(ohficeFax.value)">Fax</button>
|
|
||||||
|
|
||||||
<!-- enums in bindings -->
|
|
||||||
<hr>
|
|
||||||
<h2>Enums in bindings </h2>
|
|
||||||
<p>The name of the Color.Red enum is {{Color[Color.Red]}}</p>
|
|
||||||
<p>The current color number is {{color}}</p>
|
|
||||||
<p><button [style.color]="Color[color]" (click)="colorToggle()">Enum Toggle</button>
|
|
|
@ -1,299 +0,0 @@
|
||||||
// NOT EVERYTHING IS NEEDED BY TEMPLATE-SYNTAX CHAPTER
|
|
||||||
// Much left-over from support for "User Input" chapter such as
|
|
||||||
// ClickMeComponent,
|
|
||||||
// KeyUpComponent, KeyUpComponentV2, KeyUpComponentV3,
|
|
||||||
// LittleTour, LoopbackComponent,
|
|
||||||
// TODO: purge extraneous material
|
|
||||||
|
|
||||||
|
|
||||||
/// #docplaster
|
|
||||||
|
|
||||||
import {bootstrap, Component, CORE_DIRECTIVES,
|
|
||||||
Input, Output,
|
|
||||||
Directive,
|
|
||||||
ElementRef, EventEmitter,
|
|
||||||
NgForm, FORM_DIRECTIVES
|
|
||||||
} from 'angular2/angular2';
|
|
||||||
|
|
||||||
class Hero {
|
|
||||||
public id:number
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public firstName:string,
|
|
||||||
public lastName?:string,
|
|
||||||
public birthdate?:Date,
|
|
||||||
public url?:string,
|
|
||||||
public rate:number = 100) {
|
|
||||||
this.id = Hero.nextId++;
|
|
||||||
}
|
|
||||||
|
|
||||||
get fullName() {return `${this.firstName} ${this.lastName}`;}
|
|
||||||
|
|
||||||
static nextId = 1;
|
|
||||||
|
|
||||||
static MockHeroes = [
|
|
||||||
new Hero(
|
|
||||||
'Hercules',
|
|
||||||
'Son of Zeus',
|
|
||||||
new Date(1970, 1, 25),
|
|
||||||
'http://www.imdb.com/title/tt0065832/',
|
|
||||||
325),
|
|
||||||
|
|
||||||
new Hero('eenie', 'toe'),
|
|
||||||
new Hero('Meanie', 'Toe'),
|
|
||||||
new Hero('Miny', 'Toe'),
|
|
||||||
new Hero('Moe', 'Toe')
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// for fun; not used (yet)
|
|
||||||
@Directive({selector: 'select'})
|
|
||||||
class DecoratorDirective {
|
|
||||||
constructor(el: ElementRef){
|
|
||||||
console.log(el)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'hero-detail',
|
|
||||||
/*
|
|
||||||
inputs: ['hero'],
|
|
||||||
outputs: ['deleted'],
|
|
||||||
*/
|
|
||||||
template: `
|
|
||||||
<div style="border: 1px solid black; padding:3px">
|
|
||||||
<div><b>Hero Detail: {{hero?.fullName}}</b></div>
|
|
||||||
<div>First: {{hero?.firstName}}</div>
|
|
||||||
<div>Last: {{hero?.lastName}}</div>
|
|
||||||
<div>Birthdate: {{hero?.birthdate | date:'longDate'}}</div>
|
|
||||||
<div>Web: <a href="{{hero?.url}}" target="_blank">{{hero?.url}}</a></div>
|
|
||||||
<div>Rate/hr: {{hero?.rate | currency:'EUR'}}</div>
|
|
||||||
<button (click)="onDelete()">Delete</button>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
})
|
|
||||||
class HeroDetailComponent {
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
hero: Hero;
|
|
||||||
|
|
||||||
@Output()
|
|
||||||
deleted = new EventEmitter<Hero>();
|
|
||||||
|
|
||||||
onDelete() {
|
|
||||||
this.deleted.next(this.hero);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'little-hero',
|
|
||||||
template: '<div>{{hero?.fullName}}</div>'
|
|
||||||
})
|
|
||||||
class LittleHeroComponent {
|
|
||||||
@Input()
|
|
||||||
hero: Hero;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'click-me',
|
|
||||||
template: '<button (click)="onClickMe()">Click me</button>'
|
|
||||||
})
|
|
||||||
class ClickMeComponent {
|
|
||||||
onClickMe(){
|
|
||||||
alert('You are my hero!')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'loop-back',
|
|
||||||
template: '<input #box (keyup)="0"> <p>{{box.value}}</p>'
|
|
||||||
})
|
|
||||||
class LoopbackComponent {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'key-up',
|
|
||||||
template: `
|
|
||||||
<h4>Give me some keys!</h4>
|
|
||||||
<div><input (keyup)="onKey($event)"><div>
|
|
||||||
<div>{{values}}</div>
|
|
||||||
`
|
|
||||||
})
|
|
||||||
class KeyUpComponent {
|
|
||||||
values='';
|
|
||||||
onKey(event:KeyboardEvent) {
|
|
||||||
this.values += (<HTMLInputElement>event.target).value + ' | ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'key-up2',
|
|
||||||
template: `
|
|
||||||
<h4>Give me some more keys!</h4>
|
|
||||||
<div><input #box (keyup)="onKey(box.value)"><div>
|
|
||||||
<div>{{values}}</div>
|
|
||||||
`
|
|
||||||
})
|
|
||||||
class KeyUpComponentV2 {
|
|
||||||
values='';
|
|
||||||
onKey(value:string) {
|
|
||||||
this.values += value + ' | ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'key-up3',
|
|
||||||
template: `
|
|
||||||
<h4>Type away! Press [enter] when done.</h4>
|
|
||||||
<div><input #box (keyup.enter)="values=box.value"><div>
|
|
||||||
<div>{{values}}</div>
|
|
||||||
`
|
|
||||||
})
|
|
||||||
class KeyUpComponentV3 {
|
|
||||||
values='';
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'little-tour',
|
|
||||||
template: `
|
|
||||||
<h4>Little Tour of Heroes</h4>
|
|
||||||
<input #box
|
|
||||||
(keyup.enter)="addHero(box.value)"
|
|
||||||
(blur)="addHero(box.value)">
|
|
||||||
<button (click)=addHero(box.value)>Add</button>
|
|
||||||
<ul><li *ng-for="#hero of heroes">{{hero}}</li></ul>
|
|
||||||
`,
|
|
||||||
directives: [CORE_DIRECTIVES]
|
|
||||||
})
|
|
||||||
class LittleTour {
|
|
||||||
heroes=['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
|
|
||||||
|
|
||||||
addHero(newHero:string) {
|
|
||||||
if (newHero) {
|
|
||||||
this.heroes.push(newHero);
|
|
||||||
newHero = null; // clear the newHero textbox
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bootstrap(LittleTour);
|
|
||||||
|
|
||||||
enum Color {Red, Green, Blue};
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'my-app',
|
|
||||||
templateUrl: 'app/app.html',
|
|
||||||
directives: [
|
|
||||||
CORE_DIRECTIVES, FORM_DIRECTIVES,
|
|
||||||
ClickMeComponent,
|
|
||||||
KeyUpComponent, KeyUpComponentV2, KeyUpComponentV3,
|
|
||||||
LittleTour, LoopbackComponent,
|
|
||||||
HeroDetailComponent, LittleHeroComponent
|
|
||||||
]
|
|
||||||
})
|
|
||||||
class AppComponent {
|
|
||||||
|
|
||||||
actionName = 'Go for it';
|
|
||||||
callFax(value:string) {alert(`Faxing ${value} ...`)}
|
|
||||||
callPhone(value:string) {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];
|
|
||||||
|
|
||||||
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};
|
|
||||||
|
|
||||||
heroes = Hero.MockHeroes;
|
|
||||||
|
|
||||||
//heroImageUrl = 'http://www.wpclipart.com/cartoon/people/hero/hero_silhoutte_T.png';
|
|
||||||
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 : '';
|
|
||||||
alert('Canceled.'+evtMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickMe(event:KeyboardEvent){
|
|
||||||
let evtMsg = event ? ' Event target class is '+ (<HTMLElement>event.target).className : '';
|
|
||||||
alert('Click me.'+evtMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
onDeleted(hero:Hero){
|
|
||||||
alert('Deleted hero: '+ (hero && hero.firstName))
|
|
||||||
}
|
|
||||||
|
|
||||||
onSave(event:KeyboardEvent){
|
|
||||||
let evtMsg = event ? ' Event target is '+ (<HTMLElement>event.target).innerText : '';
|
|
||||||
alert('Saved.'+evtMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
onSubmit(form:NgForm){
|
|
||||||
let evtMsg = form.valid ?
|
|
||||||
' Form value is '+ JSON.stringify(form.value) :
|
|
||||||
' Form is invalid';
|
|
||||||
alert('Form submitted.'+evtMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
product = {
|
|
||||||
name: 'frimfram',
|
|
||||||
price: 42
|
|
||||||
};
|
|
||||||
|
|
||||||
setLastName(lastName:string){
|
|
||||||
console.log(lastName);
|
|
||||||
this.currentHero.lastName = lastName;
|
|
||||||
}
|
|
||||||
|
|
||||||
setClasses() {
|
|
||||||
return {
|
|
||||||
saveable: this.canSave, // true
|
|
||||||
modified: !this.isUnchanged, // false
|
|
||||||
special: this.isSpecial, // true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setStyles() {
|
|
||||||
return {
|
|
||||||
'font-style': this.canSave ? 'italic' : 'normal', // italic
|
|
||||||
'font-weight': !this.isUnchanged ? 'bold' : 'normal', // normal
|
|
||||||
'font-size': this.isSpecial ? 'larger' : 'smaller', // larger
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toeChoice(picker:HTMLFieldSetElement){
|
|
||||||
let choices = picker.children;
|
|
||||||
for (let i=0; i<choices.length; i++){
|
|
||||||
var choice = <HTMLInputElement>choices[i];
|
|
||||||
if (choice.checked) {return choice.value}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
title = 'Template Syntax'
|
|
||||||
val=2;
|
|
||||||
// villainImageUrl = 'http://www.clker.com/cliparts/u/s/y/L/x/9/villain-man-hi.png'
|
|
||||||
villainImageUrl = 'images/villain.png'
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bootstrap(AppComponent);
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
import {bootstrap} from 'angular2/platform/browser';
|
||||||
|
import {AppComponent} from './app.component';
|
||||||
|
bootstrap(AppComponent);
|
|
@ -0,0 +1,11 @@
|
||||||
|
// Useful for spying on an element
|
||||||
|
// for fun; not used (yet)
|
||||||
|
import {Directive, ElementRef} from 'angular2/core';
|
||||||
|
|
||||||
|
// set the selector for the element type to spy on.
|
||||||
|
@Directive({selector: 'select'})
|
||||||
|
export class DecoratorDirective {
|
||||||
|
constructor(el: ElementRef){
|
||||||
|
console.log(el)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
import {Component, Input, Output, EventEmitter} from 'angular2/core';
|
||||||
|
|
||||||
|
import {Hero} from './hero';
|
||||||
|
|
||||||
|
let nextHeroDetailId = 1;
|
||||||
|
|
||||||
|
// #docregion input-output-2
|
||||||
|
@Component({
|
||||||
|
// #enddocregion input-output-2
|
||||||
|
selector: 'hero-detail',
|
||||||
|
// #docregion input-output-2
|
||||||
|
inputs: ['hero'],
|
||||||
|
outputs: ['deleted'],
|
||||||
|
// #enddocregion input-output-2
|
||||||
|
template: `
|
||||||
|
<div id="lh{{id}}">
|
||||||
|
{{hero?.fullName}}
|
||||||
|
<img src="{{heroImageUrl}}" style="height:24px">
|
||||||
|
<a href="#lh{{id}}" (click)="onDelete()">delete</a>
|
||||||
|
</div>`
|
||||||
|
// #docregion input-output-2
|
||||||
|
})
|
||||||
|
// #enddocregion input-output-2
|
||||||
|
export class HeroDetailComponent {
|
||||||
|
hero: Hero;
|
||||||
|
// #docregion deleted
|
||||||
|
deleted = new EventEmitter<Hero>();
|
||||||
|
onDelete() {
|
||||||
|
this.deleted.emit(this.hero);
|
||||||
|
}
|
||||||
|
// #enddocregion
|
||||||
|
|
||||||
|
// 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';
|
||||||
|
id = nextHeroDetailId++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'big-hero-detail',
|
||||||
|
/*
|
||||||
|
inputs: ['hero'],
|
||||||
|
outputs: ['deleted'],
|
||||||
|
*/
|
||||||
|
template: `
|
||||||
|
<div style="border: 1px solid black; padding:3px">
|
||||||
|
<img src="{{heroImageUrl}}" style="float:left; margin-right:8px;">
|
||||||
|
<div><b>{{hero?.fullName}}</b></div>
|
||||||
|
<div>First: {{hero?.firstName}}</div>
|
||||||
|
<div>Last: {{hero?.lastName}}</div>
|
||||||
|
<div>Birthdate: {{hero?.birthdate | date:'longDate'}}</div>
|
||||||
|
<div>Web: <a href="{{hero?.url}}" target="_blank">{{hero?.url}}</a></div>
|
||||||
|
<div>Rate/hr: {{hero?.rate | currency:'EUR'}}</div>
|
||||||
|
<br clear="all">
|
||||||
|
<button (click)="onDelete()">Delete</button>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export class BigHeroDetailComponent extends HeroDetailComponent {
|
||||||
|
|
||||||
|
// #docregion input-output-1
|
||||||
|
@Input() hero: Hero;
|
||||||
|
@Output() deleted = new EventEmitter<Hero>();
|
||||||
|
// #enddocregion input-output-1
|
||||||
|
|
||||||
|
onDelete() {
|
||||||
|
this.deleted.emit(this.hero);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
export class Hero {
|
||||||
|
public id:number
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public firstName:string,
|
||||||
|
public lastName?:string,
|
||||||
|
public birthdate?:Date,
|
||||||
|
public url?:string,
|
||||||
|
public rate:number = 100) {
|
||||||
|
this.id = Hero.nextId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
get fullName() {return `${this.firstName} ${this.lastName}`;}
|
||||||
|
|
||||||
|
static nextId = 1;
|
||||||
|
|
||||||
|
static MockHeroes = [
|
||||||
|
new Hero(
|
||||||
|
'Hercules',
|
||||||
|
'Son of Zeus',
|
||||||
|
new Date(1970, 1, 25),
|
||||||
|
'http://www.imdb.com/title/tt0065832/',
|
||||||
|
325),
|
||||||
|
|
||||||
|
new Hero('eenie', 'toe'),
|
||||||
|
new Hero('Meanie', 'Toe'),
|
||||||
|
new Hero('Miny', 'Toe'),
|
||||||
|
new Hero('Moe', 'Toe')
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
import {Directive, Output, ElementRef, EventEmitter} from 'angular2/core';
|
||||||
|
|
||||||
|
@Directive({selector:'[my-click]'})
|
||||||
|
export class MyClickDirective {
|
||||||
|
// #docregion my-click-output-1
|
||||||
|
@Output('myClick') clicks = new EventEmitter<string>();
|
||||||
|
// #enddocregion my-click-output-1
|
||||||
|
constructor(el: ElementRef){
|
||||||
|
el.nativeElement
|
||||||
|
.addEventListener('click', (event:Event) => {
|
||||||
|
this.clicks.emit('Click!');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #docregion my-click-output-2
|
||||||
|
@Directive({
|
||||||
|
// #enddocregion my-click-output-2
|
||||||
|
selector:'[my-click2]',
|
||||||
|
// #docregion my-click-output-2
|
||||||
|
outputs:['clicks:myClick']
|
||||||
|
})
|
||||||
|
// #enddocregion my-click-output-2
|
||||||
|
export class MyClickDirective2 {
|
||||||
|
clicks = new EventEmitter<string>();
|
||||||
|
constructor(el: ElementRef){
|
||||||
|
el.nativeElement
|
||||||
|
.addEventListener('click', (event:Event) => {
|
||||||
|
this.clicks.emit('Click!');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,14 +9,12 @@
|
||||||
System.config({
|
System.config({
|
||||||
packages: {'app': {defaultExtension: 'js'}}
|
packages: {'app': {defaultExtension: 'js'}}
|
||||||
});
|
});
|
||||||
System.import('app/app');
|
System.import('app/boot');
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<my-app>Loading...</my-app>
|
<my-app>Loading...</my-app>
|
||||||
<hr>
|
|
||||||
<little-tour>Loading...</little-tour>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -4,6 +4,8 @@ img {height: 100px;}
|
||||||
.child-div {margin-left: 1em; font-weight: normal}
|
.child-div {margin-left: 1em; font-weight: normal}
|
||||||
.hidden {display: none}
|
.hidden {display: none}
|
||||||
.parent-div {margin-top: 1em; font-weight: bold}
|
.parent-div {margin-top: 1em; font-weight: bold}
|
||||||
.special {font-weight:bold;}
|
.special {font-weight:bold; font-size: x-large}
|
||||||
|
.bad {color: red;}
|
||||||
|
.curly {font-family: "Brush Script MT"}
|
||||||
.toe {margin-left: 1em; font-style: italic;}
|
.toe {margin-left: 1em; font-style: italic;}
|
||||||
little-hero {color:blue; font-size: smaller; background-color: Turquoise }
|
little-hero {color:blue; font-size: smaller; background-color: Turquoise }
|
File diff suppressed because it is too large
Load Diff
|
@ -5,6 +5,8 @@ include ../../../../_includes/_util-fns
|
||||||
we want to know about it. These user actions all raise DOM events.
|
we want to know about it. These user actions all raise DOM events.
|
||||||
In this chapter we learn to bind to those events using the Angular Event Binding syntax.
|
In this chapter we learn to bind to those events using the Angular Event Binding syntax.
|
||||||
|
|
||||||
|
[Live Example](/resources/live-examples/user-input/ts/src/plnkr.html).
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
## Binding to User Input Events
|
## Binding to User Input Events
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 76 KiB |
Loading…
Reference in New Issue