parent
f54ae8b306
commit
14de4228fc
|
@ -0,0 +1,148 @@
|
|||
// #docregion
|
||||
library template_syntax.app_component;
|
||||
|
||||
import 'dart:html';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:angular2/angular2.dart';
|
||||
import 'package:template_syntax/hero.dart';
|
||||
import 'package:template_syntax/hero_detail_component.dart';
|
||||
import 'package:template_syntax/my_click_directive.dart';
|
||||
|
||||
enum _Color { Red, Green, Blue }
|
||||
|
||||
@Component(
|
||||
selector: 'my-app',
|
||||
templateUrl: 'app_component.html',
|
||||
directives: const [
|
||||
HeroDetailComponent,
|
||||
BigHeroDetailComponent,
|
||||
MyClickDirective,
|
||||
MyClickDirective2
|
||||
])
|
||||
class AppComponent {
|
||||
String heroName;
|
||||
String help;
|
||||
String actionName = 'Go for it';
|
||||
String title = 'Template Syntax';
|
||||
String heroImageUrl = 'assets/images/hero.png';
|
||||
String villainImageUrl = 'assets/images/villain.png';
|
||||
String iconUrl = 'assets/images/ng-logo.png';
|
||||
String chosenToe;
|
||||
int val = 2;
|
||||
bool canSave = true;
|
||||
bool isActive = false;
|
||||
bool isSpecial = true;
|
||||
bool isUnchanged = true;
|
||||
bool isSelected = false;
|
||||
_Color color = _Color.Red;
|
||||
List<Hero> heroes = Hero.MockHeroes;
|
||||
Hero selectedHero = Hero.MockHeroes[0];
|
||||
Hero currentHero = Hero.MockHeroes[0];
|
||||
Hero nullHero = null;
|
||||
Map product = {'name': 'frimfram', 'price': 42};
|
||||
Event clickity;
|
||||
FormElement form;
|
||||
|
||||
Map classes = {
|
||||
'saveable': false, // true
|
||||
'modified': false, // false
|
||||
'special': false // true
|
||||
};
|
||||
|
||||
Map styles = {
|
||||
'font-style': 'normal',
|
||||
'font-weight': 'normal',
|
||||
'font-size': 'smaller'
|
||||
};
|
||||
|
||||
Map styles2 = {
|
||||
'fontStyle': 'normal',
|
||||
'fontWeight': 'normal',
|
||||
'fontSize': 'smaller'
|
||||
};
|
||||
|
||||
void alerter(String msg) => window.alert(msg);
|
||||
void callFax(String value) => alerter('Faxing $value ...');
|
||||
void callPhone(String value) => alerter('Calling $value ...');
|
||||
void colorToggle() {
|
||||
color = color == _Color.Red ? _Color.Blue : _Color.Red;
|
||||
}
|
||||
|
||||
int get getVal => val;
|
||||
|
||||
void onCancel(MouseEvent event) {
|
||||
DivElement el = event.target;
|
||||
var evtMsg = event != null ? 'Event target is ${el.innerHtml}' : '';
|
||||
alerter('Canceled. $evtMsg');
|
||||
}
|
||||
|
||||
void onClickMe(MouseEvent event) {
|
||||
DivElement el = event.target;
|
||||
var evtMsg = event != null ? 'Event target class is ${el.className}' : '';
|
||||
alerter('Click me. $evtMsg');
|
||||
}
|
||||
|
||||
bool onSave([MouseEvent event = null]) {
|
||||
var evtMsg =
|
||||
event != null ? ' Event target is ${event.target.innerHtml}' : '';
|
||||
alerter('Saved.$evtMsg');
|
||||
return false;
|
||||
}
|
||||
|
||||
void onHeroDeleted(Hero hero) => alerter('Deleted hero: ${hero.firstName}');
|
||||
|
||||
void onSubmit(NgForm form) {
|
||||
var evtMsg = form.valid
|
||||
? ' Form value is ${JSON.encode(form.value)}'
|
||||
: ' Form is invalid';
|
||||
alerter('Form submitted. $evtMsg');
|
||||
}
|
||||
|
||||
void setUpperCaseFirstName(String firstName) {
|
||||
currentHero.firstName = firstName.toUpperCase();
|
||||
}
|
||||
|
||||
String getStyles(Element el) {
|
||||
var showStyles = setStyles();
|
||||
return JSON.encode(showStyles);
|
||||
}
|
||||
|
||||
// #docregion setStyles
|
||||
Map setStyles() {
|
||||
styles['font-style'] = canSave ? 'italic' : 'normal';
|
||||
styles['font-weight'] = !isUnchanged ? 'bold' : 'normal';
|
||||
styles['font-size'] = isSpecial ? 'x-large' : 'smaller';
|
||||
return styles;
|
||||
}
|
||||
// #enddocregion setStyles
|
||||
|
||||
// #docregion setStyles2
|
||||
Map setStyles2() {
|
||||
// camelCase style properties work too [PENDING: no, they don't]
|
||||
styles2['fontStyle'] = canSave ? 'italic' : 'normal';
|
||||
styles2['fontWeight'] = !isUnchanged ? 'bold' : 'normal';
|
||||
styles2['fontSize'] = isSpecial ? 'x-large' : 'smaller';
|
||||
return styles2;
|
||||
}
|
||||
// #enddocregion setStyles2
|
||||
|
||||
Map setClasses() {
|
||||
classes['saveable'] = canSave;
|
||||
classes['modified'] = !isUnchanged;
|
||||
classes['special'] = isSpecial;
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
String toeChooser(Element picker) {
|
||||
List<Element> choices = picker.children;
|
||||
for (var i = 0; i < choices.length; i++) {
|
||||
var choice = choices[i];
|
||||
if (choice.checked) {
|
||||
chosenToe = choice.value;
|
||||
return chosenToe;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,667 @@
|
|||
<!-- #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="assets/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 [ngClass] = "{selected: isSelected}"></div>
|
||||
<!-- #enddocregion property-binding-syntax-1 -->
|
||||
</div>
|
||||
<br><br>
|
||||
|
||||
<!-- See https://github.com/angular/angular/issues/5707 about "myClick (myClick)" -->
|
||||
<!-- #docregion event-binding-syntax-1 -->
|
||||
<button (click) = "onSave()">Save</button>
|
||||
<hero-detail (deleted)="onHeroDeleted()"></hero-detail>
|
||||
<div myClick (myClick)="clicked=$event">click me</div>
|
||||
<!-- #enddocregion event-binding-syntax-1 -->
|
||||
<!-- {{clicked}} --> <!-- causes exception in Dart version -->
|
||||
<br><br>
|
||||
|
||||
<div>
|
||||
<!-- #docregion 2-way-binding-syntax-1 -->
|
||||
<input [(ngModel)]="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>
|
||||
|
||||
<!-- property vs. attribute -->
|
||||
<hr><h2>Property vs. Attribute (img examples)</h2>
|
||||
<!-- examine the following <img> tag in the browser tools -->
|
||||
<img src="assets/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 [ngClass]="'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>--> <!--THROWS ERROR IN DART-->
|
||||
<!-- #enddocregion property-binding-6 -->
|
||||
|
||||
<!-- #docregion property-binding-vs-interpolation -->
|
||||
<img src="{{heroImageUrl}}">
|
||||
<img [src]="'' + heroImageUrl">
|
||||
|
||||
<div>The title is {{title}}</div>
|
||||
<div [textContent]="'The title is '+title"></div>
|
||||
<!-- #enddocregion property-binding-vs-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 -->
|
||||
<!-- `myClick` is an event on the custom `MyClickDirective` -->
|
||||
|
||||
<!-- #docregion my-click -->
|
||||
<div myClick (myClick)="clickity=$event">click with myClick</div>
|
||||
<!-- #enddocregion my-click -->
|
||||
<!-- #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 [(ngModel)]="currentHero.firstName">
|
||||
<!-- #enddocregion NgModel-1 -->
|
||||
[(ngModel)]
|
||||
<br>
|
||||
<!-- #docregion NgModel-2 -->
|
||||
<input bindon-ngModel="currentHero.firstName">
|
||||
<!-- #enddocregion NgModel-2 -->
|
||||
bindon-ngModel
|
||||
<br>
|
||||
<!-- #docregion NgModel-3 -->
|
||||
<input
|
||||
[ngModel]="currentHero.firstName"
|
||||
(ngModelChange)="currentHero.firstName=$event">
|
||||
<!-- #enddocregion NgModel-3 -->
|
||||
(ngModelChange) = "...firstName=$event"
|
||||
<br>
|
||||
<!-- #docregion NgModel-4 -->
|
||||
<input
|
||||
[ngModel]="currentHero.firstName"
|
||||
(ngModelChange)="setUpperCaseFirstName($event)">
|
||||
<!-- #enddocregion NgModel-4 -->
|
||||
(ngModelChange) = "setUpperCaseFirstName($event)"
|
||||
<br>
|
||||
|
||||
|
||||
|
||||
<!-- NgClass binding -->
|
||||
<hr><h2>NgClass Binding</h2>
|
||||
|
||||
<p>setClasses returns {{setClasses() | json}}</p>
|
||||
<!-- #docregion NgClass-1 -->
|
||||
<div [ngClass]="setClasses()">This div is saveable and special</div>
|
||||
<!-- #enddocregion NgClass-1 -->
|
||||
<div [ngClass]="setClasses()" #classDiv>
|
||||
After setClasses(), the classes are "{{classDiv.className}}"
|
||||
</div>
|
||||
|
||||
<!-- not used in chapter -->
|
||||
|
||||
<div [ngClass]="isSpecial ? 'special' : ''">This div is special</div>
|
||||
|
||||
<div class="bad curly special">Bad curly special</div>
|
||||
<div [ngClass]="{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 -->
|
||||
|
||||
<h3>Use setStyles() - CSS property names</h3>
|
||||
<p>setStyles returns {{setStyles() | json}}</p>
|
||||
<!-- #docregion NgStyle-2 -->
|
||||
<div [ngStyle]="setStyles()">
|
||||
This div is italic, normal weight, and x-large
|
||||
</div>
|
||||
<!-- #enddocregion NgStyle-2 -->
|
||||
<div [ngStyle]="setStyles()" #styleDiv>
|
||||
After setStyles(), the styles are "{{getStyles(styleDiv)}}"
|
||||
</div>
|
||||
|
||||
|
||||
<h3>Use setStyles2() - camelCase style property names</h3>
|
||||
<p>setStyles2 returns {{setStyles2() | json}}</p>
|
||||
<!-- #docregion NgStyle-3 -->
|
||||
<div [ngStyle]="setStyles2()">
|
||||
This div is italic, normal weight, and x-large
|
||||
</div>
|
||||
<!-- #enddocregion NgStyle-3 -->
|
||||
<div [ngStyle]="setStyles2()" #styleDiv2>
|
||||
After setStyles2(), the styles are "{{getStyles(styleDiv2)}}"
|
||||
</div>
|
||||
|
||||
<!-- not used in chapter -->
|
||||
|
||||
|
||||
|
||||
<!-- NgIf binding -->
|
||||
<hr><h2>NgIf Binding</h2>
|
||||
|
||||
<!-- #docregion NgIf-1 -->
|
||||
<div *ngIf="currentHero != null">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 *ngIf="nullHero != null">Hello, {{nullHero.firstName}}</div>
|
||||
|
||||
<!-- Hero Detail is not in the DOM because isActive is false-->
|
||||
<hero-detail *ngIf="isActive"></hero-detail>
|
||||
<!-- #enddocregion NgIf-2 -->
|
||||
|
||||
|
||||
<!-- NgIf binding with template (no *) -->
|
||||
|
||||
<template [ngIf]="currentHero != null">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 [ngIf]="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 #toePicker (click)="toeChooser(toePicker)" >
|
||||
<input type="radio" name="toes" value="Eenie">Eenie
|
||||
<input type="radio" name="toes" 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">
|
||||
<div *ngIf="chosenToe == null">Pick a toe</div>
|
||||
<div *ngIf="chosenToe != null">You picked
|
||||
<!-- #docregion NgSwitch -->
|
||||
<span [ngSwitch]="chosenToe">
|
||||
<template [ngSwitchWhen]="'Eenie'">Eenie</template>
|
||||
<template [ngSwitchWhen]="'Meanie'">Meanie</template>
|
||||
<template [ngSwitchWhen]="'Miney'">Miney</template>
|
||||
<template [ngSwitchWhen]="'Moe'">Moe</template>
|
||||
<template ngSwitchDefault>Other</template>
|
||||
</span>
|
||||
<!-- #enddocregion NgSwitch -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- NgFor binding -->
|
||||
<hr><h2>NgFor Binding</h2>
|
||||
|
||||
<div class="box">
|
||||
<!-- #docregion NgFor-1 -->
|
||||
<div *ngFor="#hero of heroes">{{hero.fullName}}</div>
|
||||
<!-- #enddocregion NgFor-1 -->
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="box">
|
||||
<!-- *ngFor w/ hero-detail Component -->
|
||||
<!-- #docregion NgFor-2 -->
|
||||
<hero-detail *ngFor="#hero of heroes" [hero]="hero"></hero-detail>
|
||||
<!-- #enddocregion NgFor-2 -->
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="box">
|
||||
<!-- #docregion NgFor-3 -->
|
||||
<!-- Ex: 1 - Hercules Son of Zeus -->
|
||||
<div *ngFor="#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 *ngIf="currentHero != null" [hero]="currentHero"></hero-detail>
|
||||
<!-- #enddocregion Template-1 -->
|
||||
|
||||
<!-- #docregion Template-2 -->
|
||||
<template [ngIf]="currentHero != null">
|
||||
<hero-detail [hero]="currentHero"></hero-detail>
|
||||
</template>
|
||||
<!-- #enddocregion Template-2 -->
|
||||
|
||||
<h3>NgFor expansion</h3>
|
||||
<div class="box">
|
||||
<!-- ngFor w/ hero-detail Component and a template "attribute" directive -->
|
||||
<!-- #docregion Template-3 -->
|
||||
<hero-detail template="ngFor #hero of heroes" [hero]="hero"></hero-detail>
|
||||
<!-- #enddocregion Template-3 -->
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="box">
|
||||
<!-- ngFor w/ hero-detail Component inside a template element -->
|
||||
<!-- #docregion Template-4 -->
|
||||
<template ngFor #hero [ngForOf]="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 (ngSubmit)="onSubmit(theForm)" #theForm="ngForm">
|
||||
<!-- #enddocregion var-form-a -->
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<input id="name" class="form-control" required ngControl="firstName"
|
||||
[(ngModel)]="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 [textContent]="'disabled by attribute: ' + btn.disabled.toString()"></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 myClick2 (myClick)="clicked2=$event">myClick2</div>
|
||||
{{clicked2}}
|
||||
PENDING: I don't see clicked2 defined anywhere in the TS example
|
||||
-->
|
||||
|
||||
<!-- 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>--> <!-- PENDING: uncomment? -->
|
||||
|
||||
<!-- 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}}--> <!-- PENDING: uncomment? -->
|
||||
</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 *ngIf="nullHero != null">The null hero's name is {{nullHero.firstName}}</div>
|
||||
<!-- #enddocregion elvis-4 -->
|
||||
|
||||
<div>
|
||||
<!-- #docregion elvis-5 -->
|
||||
The null hero's name is {{nullHero != null && nullHero.firstName != null}} <!-- PENDING: ??? -->
|
||||
<!-- #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}}</p> <!-- PENDING: Color[Color.Red]?? -->
|
||||
<p>The current color number is {{color}}</p>
|
||||
<p><button [style.color]="color" (click)="colorToggle()">Enum Toggle</button> <!-- PENDING: color -> Color[color]? -->
|
Binary file not shown.
After Width: | Height: | Size: 8.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
|
@ -0,0 +1,31 @@
|
|||
// #docregion
|
||||
library template_syntax.hero;
|
||||
|
||||
class Hero {
|
||||
static int _nextId = 1;
|
||||
|
||||
int id;
|
||||
String firstName;
|
||||
String lastName;
|
||||
DateTime birthdate;
|
||||
String url;
|
||||
int rate = 100;
|
||||
|
||||
Hero(this.firstName, {this.lastName, this.birthdate, this.url, this.rate}) {
|
||||
id = _nextId++;
|
||||
}
|
||||
|
||||
static List<Hero> MockHeroes = [
|
||||
new Hero('Hercules',
|
||||
lastName: 'Son of Zeus',
|
||||
birthdate: new DateTime(1970, 1, 25),
|
||||
url: 'http://www.imdb.com/title/tt0065832/',
|
||||
rate: 325),
|
||||
new Hero('eenie', lastName: 'toe'),
|
||||
new Hero('Meanie', lastName: 'Toe'),
|
||||
new Hero('Miny', lastName: 'Toe'),
|
||||
new Hero('Moe', lastName: 'Toe')
|
||||
];
|
||||
|
||||
String get fullName => '$firstName $lastName';
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
// #docregion
|
||||
library template_syntax.hero_detail_component;
|
||||
|
||||
import 'package:angular2/angular2.dart';
|
||||
import 'package:template_syntax/hero.dart';
|
||||
|
||||
var nextHeroDetailId = 1;
|
||||
|
||||
// #docregion input-output-2
|
||||
@Component(
|
||||
// #enddocregion input-output-2
|
||||
selector: 'hero-detail',
|
||||
// #docregion input-output-2
|
||||
inputs: const ['hero'],
|
||||
outputs: const ['deleted'],
|
||||
// #enddocregion input-output-2
|
||||
template: '''<div id="lh{{hero?.id}}">
|
||||
{{hero?.fullName}}
|
||||
<img src="{{heroImageUrl}}" style="height:24px">
|
||||
<a href="#lh{{hero?.id}}" (click)="onDelete()">delete</a>
|
||||
</div>'''
|
||||
// #docregion input-output-2
|
||||
)
|
||||
// #enddocregion input-output-2
|
||||
class HeroDetailComponent {
|
||||
Hero hero;
|
||||
// #docregion deleted
|
||||
|
||||
String heroImageUrl = 'assets/images/hero.png';
|
||||
final EventEmitter deleted = new EventEmitter<Hero>();
|
||||
|
||||
onDelete() {
|
||||
deleted.add(hero);
|
||||
}
|
||||
// #enddocregion deleted
|
||||
}
|
||||
|
||||
@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>''')
|
||||
class BigHeroDetailComponent extends HeroDetailComponent {
|
||||
// #docregion input-output-1
|
||||
@Input() Hero hero;
|
||||
@Output()
|
||||
final EventEmitter deleted = new EventEmitter<Hero>();
|
||||
// #enddocregion input-output-1
|
||||
|
||||
String heroImageUrl = 'assets/images/hero.png';
|
||||
|
||||
onDelete() {
|
||||
deleted.add(hero);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
// #docregion
|
||||
library template_syntax.my_click_directive;
|
||||
|
||||
import 'dart:html';
|
||||
|
||||
import 'package:angular2/angular2.dart';
|
||||
|
||||
@Directive(selector: '[myClick]')
|
||||
class MyClickDirective {
|
||||
// #docregion my-click-output-1
|
||||
@Output()
|
||||
final EventEmitter clicks = new EventEmitter<String>();
|
||||
// #enddocregion my-click-output-1
|
||||
|
||||
MyClickDirective(ElementRef el) {
|
||||
el.nativeElement.onClick.listen(this.clicks.add('Click!'));
|
||||
}
|
||||
}
|
||||
|
||||
// #docregion my-click-output-2
|
||||
@Directive(
|
||||
// #enddocregion my-click-output-2
|
||||
selector: '[myClick2]',
|
||||
// #docregion my-click-output-2
|
||||
outputs: const ['clicks:myClick'])
|
||||
// #enddocregion my-click-output-2
|
||||
class MyClickDirective2 {
|
||||
final EventEmitter clicks = new EventEmitter<String>();
|
||||
|
||||
MyClickDirective(ElementRef el) {
|
||||
el.nativeElement.onClick.listen(this.clicks.add('Click!'));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
name: template_syntax
|
||||
description: Template Syntax
|
||||
version: 0.0.1
|
||||
dependencies:
|
||||
angular2: 2.0.0-beta.0
|
||||
browser: ^0.10.0
|
||||
transformers:
|
||||
- angular2:
|
||||
platform_directives:
|
||||
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
|
||||
- 'package:angular2/common.dart#FORM_DIRECTIVES'
|
||||
entry_points: web/main.dart
|
Binary file not shown.
After Width: | Height: | Size: 8.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
|
@ -0,0 +1,13 @@
|
|||
<!--#docregion-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Template Syntax</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script defer src="main.dart" type="application/dart"></script>
|
||||
<script defer src="packages/browser/dart.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<my-app>Loading...</my-app>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,7 @@
|
|||
// #docregion
|
||||
import 'package:angular2/bootstrap.dart';
|
||||
import 'package:template_syntax/app_component.dart';
|
||||
|
||||
main() {
|
||||
bootstrap(AppComponent);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fieldset {border-style:none}
|
||||
img {height: 100px;}
|
||||
.box {border: 1px solid black; padding:3px}
|
||||
.child-div {margin-left: 1em; font-weight: normal}
|
||||
.hidden {display: none}
|
||||
.parent-div {margin-top: 1em; 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;}
|
||||
little-hero {color:blue; font-size: smaller; background-color: Turquoise }
|
Loading…
Reference in New Issue