(docs) devguide add template-syntax example

This commit is contained in:
Ward Bell 2015-10-31 14:44:36 -07:00 committed by Naomi Black
parent 92563e612a
commit acdc9b5f7b
10 changed files with 746 additions and 0 deletions

View File

@ -0,0 +1 @@
src/**/*.js

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

View File

@ -0,0 +1,21 @@
{
"name": "angular2-template-syntax",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"tsc": "tsc -p src -w",
"start": "live-server --open=src"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"angular2": "2.0.0-alpha.44",
"systemjs": "0.19.2"
},
"devDependencies": {
"live-server": "^0.8.1",
"typescript": "^1.6.2"
}
}

View File

@ -0,0 +1,378 @@
<!-- 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>
<!-- #docregion click-me-button -->
<button (click)="onClickMe()">Click me!</button>
<!-- #enddocregion 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>

View File

@ -0,0 +1,304 @@
//**** Referenced in template-syntax and user-input chapters
// #docplaster
// imports formatted for dev guide only
// #docregion little-tour-of-heroes-app
import {bootstrap, Component, CORE_DIRECTIVES} from 'angular2/angular2';
// #enddocregion little-tour-of-heroes-app
import {
Input, Output,
Directive,
ElementRef, EventEmitter,
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();
onDelete() {
this.deleted.next(this.hero);
}
}
@Component({
selector: 'little-hero',
template: '<div>{{hero?.fullName}}</div>'
})
class LittleHeroComponent {
@Input()
hero: Hero;
}
// #docregion click-me-component
@Component({
selector: 'click-me',
template: '<button (click)="onClickMe()">Click me</button>'
})
class ClickMeComponent {
onClickMe(){
alert('You are my hero!')
}
}
// #enddocregion click-me-component
// #docregion loop-back-component
@Component({
selector: 'loop-back',
template: '<input #box (keyup)="0"> <p>{{box.value}}</p>'
})
class LoopbackComponent {
}
// #enddocregion loop-back-component
// #docregion key-up-component
@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) {
this.values += event.target.value + ' | ';
}
}
// #enddocregion key-up-component
// #docregion key-up2-component
@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) {
this.values += value + ' | ';
}
}
// #enddocregion key-up2-component
// #docregion key-up3-component
@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='';
}
// #enddocregion key-up3-component
// #docregion little-tour-of-heroes-app
// #docregion little-tour-of-heroes-component
@Component({
selector: 'little-tour',
template: `
<h4>Little Tour of Heroes</h4>
<input #new-hero (keyup.enter)="addHero(newHero)">
<button (click)=addHero(newHero)>Add</button>
<ul><li *ng-for="#hero of heroes">{{hero}}</li></ul>
`,
directives: [CORE_DIRECTIVES]
})
class LittleTour {
heroes=['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
addHero(newHero) {
if (newHero.value) {
this.heroes.push(newHero.value);
newHero.value = null; // clear the newHero textbox
}
}
}
// #enddocregion little-tour-of-heroes-component
bootstrap(LittleTour);
// #enddocregion little-tour-of-heroes-app
@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;
currentHero = Hero.MockHeroes[0];
getStyles(el){
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){
let evtMsg = event ? ' Event target is '+ event.target.innerHTML : '';
alert('Canceled.'+evtMsg)
}
onClickMe(event){
let evtMsg = event ? ' Event target class is '+ event.target.className : '';
alert('Click me.'+evtMsg)
}
onDeleted(hero){
alert('Deleted hero: '+ (hero && hero.firstName))
}
onSave(event){
let evtMsg = event ? ' Event target is '+ event.target.innerText : '';
alert('Saved.'+evtMsg)
}
onSubmit(form){
let evtMsg = form.valid ?
' Form value is '+ JSON.stringify(form.value) :
' Form is invalid';
alert('Form submitted.'+evtMsg)
}
product = {
name: 'frimfram',
price: 42
};
setLastName(event){
console.log(event);
this.currentHero.lastName = event;
}
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){
let choices = picker.children;
for (let i=0; i<choices.length; i++){
if (choices[i].checked) {return choices[i].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);

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<title>Template Syntax</title>
<link rel="stylesheet" href="styles.css">
<script src="../node_modules/systemjs/dist/system.src.js"></script>
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
<script>
System.config({
packages: {'app': {defaultExtension: 'js'}}
});
System.import('app/app');
</script>
</head>
<body>
<my-app>Loading...</my-app>
<hr>
<little-tour>Loading...</little-tour>
</body>
</html>

View File

@ -0,0 +1,9 @@
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;}
.toe {margin-left: 1em; font-style: italic;}
little-hero {color:blue; font-size: smaller; background-color: Turquoise }

View File

@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "ES5",
"module": "commonjs",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
}
}