docs(Template Syntax): update to a.53 (kebab work)

closes #493
This commit is contained in:
Ward Bell 2015-12-13 20:10:03 -08:00
parent 31051d29f0
commit 7cf097ea68
14 changed files with 193 additions and 233 deletions

View File

@ -23,7 +23,7 @@
<!-- #docregion sum-2 -->
<!-- "The sum of 1 + 1 is not 4" -->
<p>The sum of 1 + 1 is not {{1+1+getVal()}}</p>
<p>The sum of 1 + 1 is not {{1 + 1 + getVal()}}</p>
<!-- #enddocregion sum-2 -->
@ -60,22 +60,23 @@
<!-- #docregion property-binding-syntax-1 -->
<img [src] = "heroImageUrl">
<hero-detail [hero]="currentHero"></hero-detail>
<div [ng-class] = "{selected: isSelected}"></div>
<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 my-click (my-click)="clicked=$event">click me</div>
<div myClick (myClick)="clicked=$event">click me</div>
<!-- #enddocregion event-binding-syntax-1 -->
{{clicked}}
<br><br>
<div>
<!-- #docregion 2-way-binding-syntax-1 -->
<input [(ng-model)]="heroName">
<input [(ngModel)]="heroName">
<!-- #enddocregion 2-way-binding-syntax-1 -->
Hero Name: {{heroName}}
</div>
@ -96,20 +97,6 @@
<!-- #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 -->
@ -148,7 +135,7 @@ button</button>
<button [disabled]="isUnchanged">Cancel</button>
<!-- #enddocregion property-binding-2 -->
<!-- #docregion property-binding-3 -->
<div [ng-class]="'special'">NgClass is special</div>
<div [ngClass]="'special'">NgClass is special</div>
<!-- #enddocregion property-binding-3 -->
<!-- #docregion property-binding-4 -->
<hero-detail [hero]="selectedHero"></hero-detail>
@ -162,13 +149,13 @@ button</button>
<hero-detail hero="…what do we do here??? …"></hero-detail>
<!-- #enddocregion property-binding-6 -->
<!-- #docregion property-binding-v-interpolation -->
<!-- #docregion property-binding-vs-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 -->
<div [textContent]="'The title is '+title"></div>
<!-- #enddocregion property-binding-vs-interpolation -->
<!-- attribute binding -->
<hr><h2>Attribute Binding</h2>
@ -180,7 +167,7 @@ button</button>
<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 colspan="{{1 + 1}}">Three-Four</td></tr>
-->
<tr><td>Five</td><td>Six</td></tr>
@ -246,12 +233,12 @@ button</button>
<!-- #docregion style-binding-1 -->
<button [style.color] = "isSpecial ? 'red' : 'green'">Red</button>
<button [style.background-color]="canSave ?'cyan' : 'grey'" >Save</button>
<button [style.backgroundColor]="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>
<button [style.fontSize.em]="isSpecial ? 3 : 1" >Big</button>
<button [style.fontSize.%]="!isSpecial ? 150 : 50" >Small</button>
<!-- #enddocregion style-binding-2 -->
<!-- event binding -->
@ -267,8 +254,8 @@ button</button>
<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>
<!-- `myClick` is an event on the custom `MyClickDirective` -->
<div myClick (myClick)="clickity=$event">click with myClick</div>
<!-- #enddocregion event-binding-3 -->
{{clickity}}
</div>
@ -322,28 +309,28 @@ button</button>
without NgModel
<br>
<!-- #docregion NgModel-1 -->
<input [(ng-model)]="currentHero.firstName">
<input [(ngModel)]="currentHero.firstName">
<!-- #enddocregion NgModel-1 -->
[(ng-model)]
[(ngModel)]
<br>
<!-- #docregion NgModel-2 -->
<input bindon-ng-model="currentHero.firstName">
<input bindon-ngModel="currentHero.firstName">
<!-- #enddocregion NgModel-2 -->
bindon-ng-model
bindon-ngModel
<br>
<!-- #docregion NgModel-3 -->
<input
[ng-model]="currentHero.firstName"
(ng-model-change)="currentHero.firstName=$event">
[ngModel]="currentHero.firstName"
(ngModelChange)="currentHero.firstName=$event">
<!-- #enddocregion NgModel-3 -->
(ng-model-change) = "...firstName=$event"
(ngModelChange) = "...firstName=$event"
<br>
<!-- #docregion NgModel-4 -->
<input
[ng-model]="currentHero.firstName"
(ng-model-change)="setUpperCaseFirstName($event)">
[ngModel]="currentHero.firstName"
(ngModelChange)="setUpperCaseFirstName($event)">
<!-- #enddocregion NgModel-4 -->
(ng-model-change) = "setUpperCaseFirstName($event)"
(ngModelChange) = "setUpperCaseFirstName($event)"
<br>
@ -353,36 +340,36 @@ bindon-ng-model
<p>setClasses returns {{setClasses() | json}}</p>
<!-- #docregion NgClass-1 -->
<div [ng-class]="setClasses()">This div is saveable and special</div>
<div [ngClass]="setClasses()">This div is saveable and special</div>
<!-- #enddocregion NgClass-1 -->
<div [ng-class]="setClasses()" #class-div>
<div [ngClass]="setClasses()" #classDiv>
After setClasses(), the classes are "{{classDiv.className}}"
</div>
<!-- not used in chapter -->
<div [ng-class]="isSpecial ? 'special' : ''">This div is special</div>
<div [ngClass]="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>
<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'" >
<div [style.fontSize]="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()">
<div [ngStyle]="setStyles()">
This div is italic, normal weight, and x-large
</div>
<!-- #enddocregion NgStyle-2 -->
<div [ng-style]="setStyles()" #style-div>
<div [ngStyle]="setStyles()" #styleDiv>
After setStyles(), the styles are "{{getStyles(styleDiv)}}"
</div>
@ -394,26 +381,26 @@ After setClasses(), the classes are "{{classDiv.className}}"
<hr><h2>NgIf Binding</h2>
<!-- #docregion NgIf-1 -->
<div *ng-if="currentHero">Hello, {{currentHero.firstName}}</div>
<div *ngIf="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>
<div *ngIf="nullHero">Hello, {{nullHero.firstName}}</div>
<!-- Hero Detail is not in the DOM because isActive is false-->
<hero-detail *ng-if="isActive"></hero-detail>
<hero-detail *ngIf="isActive"></hero-detail>
<!-- #enddocregion NgIf-2 -->
<!-- NgIf binding with template (no *) -->
<template [ng-if]="currentHero">Add {{currentHero.firstName}} with template</template>
<template [ngIf]="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">
<template [ngIf]="isActive">
<hero-detail></hero-detail>
</template>
@ -434,7 +421,7 @@ After setClasses(), the classes are "{{classDiv.className}}"
<!-- NgSwitch binding -->
<hr><h2>NgSwitch Binding</h2>
<fieldset #toe-picker (click)="null" >
<fieldset #toePicker (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
@ -443,12 +430,12 @@ After setClasses(), the classes are "{{classDiv.className}}"
</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 [ngSwitch]="toeChoice(toePicker)">
<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>
</div>
<!-- #enddocregion NgSwitch -->
@ -459,15 +446,15 @@ After setClasses(), the classes are "{{classDiv.className}}"
<div class="box">
<!-- #docregion NgFor-1 -->
<div *ng-for="#hero of heroes">{{hero.fullName}}</div>
<div *ngFor="#hero of heroes">{{hero.fullName}}</div>
<!-- #enddocregion NgFor-1 -->
</div>
<br>
<div class="box">
<!-- *ng-for w/ hero-detail Component -->
<!-- *ngFor w/ hero-detail Component -->
<!-- #docregion NgFor-2 -->
<hero-detail *ng-for="#hero of heroes" [hero]="hero"></hero-detail>
<hero-detail *ngFor="#hero of heroes" [hero]="hero"></hero-detail>
<!-- #enddocregion NgFor-2 -->
</div>
<br>
@ -475,7 +462,7 @@ After setClasses(), the classes are "{{classDiv.className}}"
<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>
<div *ngFor="#hero of heroes, #i=index">{{i+1}} - {{hero.fullName}}</div>
<!-- #enddocregion NgFor-3 -->
</div>
<br>
@ -485,28 +472,28 @@ After setClasses(), the classes are "{{classDiv.className}}"
<h3>NgIf expansion</h3>
<!-- #docregion Template-1 -->
<hero-detail *ng-if="currentHero" [hero]="currentHero"></hero-detail>
<hero-detail *ngIf="currentHero" [hero]="currentHero"></hero-detail>
<!-- #enddocregion Template-1 -->
<!-- #docregion Template-2 -->
<template [ng-if]="currentHero">
<template [ngIf]="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 -->
<!-- ngFor w/ hero-detail Component and a template "attribute" directive -->
<!-- #docregion Template-3 -->
<hero-detail template="ng-for #hero of heroes" [hero]="hero"></hero-detail>
<hero-detail template="ngFor #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 -->
<!-- ngFor w/ hero-detail Component inside a template element -->
<!-- #docregion Template-4 -->
<template ng-for #hero [ng-for-of]="heroes">
<template ngFor #hero [ngForOf]="heroes">
<hero-detail [hero]="hero"></hero-detail>
</template>
<!-- #enddocregion Template-4 -->
@ -530,12 +517,12 @@ After setClasses(), the classes are "{{classDiv.className}}"
<h4>Example Form</h4>
<!-- #docregion var-form -->
<!-- #docregion var-form-a -->
<form (ng-submit)="onSubmit(theForm)" #theForm="form">
<form (ngSubmit)="onSubmit(theForm)" #theForm="ngForm">
<!-- #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">
<input class="form-control" required ngControl="firstName"
[(ngModel)]="currentHero.firstName">
</div>
<!-- #docregion var-form-a -->
<button type="submit" [disabled]="!theForm.form.valid">Submit</button>
@ -545,7 +532,7 @@ After setClasses(), the classes are "{{classDiv.className}}"
<br><br>
<!-- btn refers to the button element; show its disabled state -->
<button #btn disabled [text-content]="'disabled by attribute: '+btn.disabled"></button>
<button #btn disabled [textContent]="'disabled by attribute: '+btn.disabled"></button>
<!-- inputs and output -->
<hr><h2>Inputs and Outputs</h2>
@ -560,7 +547,7 @@ After setClasses(), the classes are "{{classDiv.className}}"
</hero-detail>
<!-- #enddocregion io-2 -->
<div my-click2 (my-click)="clicked2=$event">my-click2</div>
<div myClick2 (myClick)="clicked2=$event">myClick2</div>
{{clicked2}}
<!-- Pipes -->
@ -632,7 +619,7 @@ See console log
<!-- #docregion elvis-4 -->
<!--No hero, div not displayed, no error -->
<div *ng-if="nullHero">The null hero's name is {{nullHero.firstName}}</div>
<div *ngIf="nullHero">The null hero's name is {{nullHero.firstName}}</div>
<!-- #enddocregion elvis-4 -->
<div>

View File

@ -1,10 +1,10 @@
import {Directive, Output, ElementRef, EventEmitter} from 'angular2/core';
@Directive({selector:'[my-click]'})
@Directive({selector:'[mClick]'})
export class MyClickDirective {
// #docregion my-click-output-1
// #docregion myClick-output-1
@Output('myClick') clicks = new EventEmitter<string>();
// #enddocregion my-click-output-1
// #enddocregion myClick-output-1
constructor(el: ElementRef){
el.nativeElement
.addEventListener('click', (event:Event) => {
@ -13,14 +13,14 @@ export class MyClickDirective {
}
}
// #docregion my-click-output-2
// #docregion myClick-output-2
@Directive({
// #enddocregion my-click-output-2
selector:'[my-click2]',
// #docregion my-click-output-2
// #enddocregion myClick-output-2
selector:'[myClick2]',
// #docregion myClick-output-2
outputs:['clicks:myClick']
})
// #enddocregion my-click-output-2
// #enddocregion myClick-output-2
export class MyClickDirective2 {
clicks = new EventEmitter<string>();
constructor(el: ElementRef){

View File

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -24,7 +24,7 @@ include ../../../../_includes/_util-fns
>[Event Binding](#event-binding)
>[Two-way data binding with `NgModel`](#ng-model)
>[Two-way data binding with `NgModel`](#ngModel)
>[Built-in Directives](#directives)
@ -36,14 +36,14 @@ include ../../../../_includes/_util-fns
>[Template Expression Operators](#expression-operators)
[Live Example](/resources/live-examples/template-syntax/ts/src/plnkr.html).
[Live Example](/resources/live-examples/template-syntax/ts/plnkr.html).
.l-main-section
:marked
## HTML
HTML is the language of the Angular template. Our “[QuickStart](./quickstart.html)” application had a template that was pure HTML
+makeExample('template-syntax/ts/src/app/app.component.html', 'my-first-app')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'my-first-app')(format=".")
:marked
Almost all HTML syntax is valid template syntax. The `<script>` element is a notable exception; it is forbidden in order to eliminate any possibility of JavaScript injection attacks (in practice it is simply ignored).
@ -57,11 +57,11 @@ include ../../../../_includes/_util-fns
:marked
## Interpolation
We met the double-curly braces of interpolation, `{{` and `}}`, early in our Angular education.
+makeExample('template-syntax/ts/src/app/app.component.html', 'first-interpolation')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'first-interpolation')(format=".")
:marked
We use interpolation to weave calculated strings into the text between HTML element tags and within attribute assignments.
+makeExample('template-syntax/ts/src/app/app.component.html', 'title+image')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'title+image')(format=".")
:marked
The material between the braces is often the name of a component property. Angular replaces that name with the
string value of the corresponding component property. In this example, Angular evaluates the `title` and `heroImageUrl` properties
@ -69,10 +69,10 @@ include ../../../../_includes/_util-fns
More generally, the material between the braces is a **template expression** that Angular first **evaluates**
and then **converts to a string**. The following interpolation illustrates the point by adding the two numbers within braces:
+makeExample('template-syntax/ts/src/app/app.component.html', 'sum-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'sum-1')(format=".")
:marked
The expression can invoke methods of the host component as we do here with `getVal()`:
+makeExample('template-syntax/ts/src/app/app.component.html', 'sum-2')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'sum-2')(format=".")
:marked
Angular evaluates all expressions in double curly braces, converts the expression results to strings, and concatenates them with neighboring literal strings. Finally,
it assigns this composite interpolated result to an **element or directive property**.
@ -194,19 +194,19 @@ table
In the normal course of HTML development, we create a visual structure with HTML elements and
we modify those elements by setting element attributes with string constants.
+makeExample('template-syntax/ts/src/app/app.component.html', 'img+button')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'img+button')(format=".")
:marked
We still create a structure and initialize attribute values this way in Angular templates.
Then we learn to create new elements with Components that encapsulate HTML
and drop them into our templates as if they were native HTML elements
+makeExample('template-syntax/ts/src/app/app.component.html', 'hero-detail-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'hero-detail-1')(format=".")
:marked
Thats “HTML Plus”.
Now we start to learn about data binding. The first binding we meet might look like this:
+makeExample('template-syntax/ts/src/app/app.component.html', 'disabled-button-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'disabled-button-1')(format=".")
:marked
Well get to that peculiar bracket notation in a moment. Looking beyond it,
our intuition tells us that were binding to the button's `disabled` attribute and setting
@ -293,7 +293,7 @@ table
Component&nbsp;Property<br>
Directive&nbsp;property
td
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-syntax-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-syntax-1')(format=".")
tr
td Event
td.
@ -301,61 +301,34 @@ table
Component&nbsp;Event<br>
Directive&nbsp;Event
td
+makeExample('template-syntax/ts/src/app/app.component.html', 'event-binding-syntax-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-syntax-1')(format=".")
tr
td Two-way
td.
Directive&nbsp;Event
Property
td
+makeExample('template-syntax/ts/src/app/app.component.html', '2-way-binding-syntax-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', '2-way-binding-syntax-1')(format=".")
tr
td Attribute
td.
Attribute
(the&nbsp;exception)
td
+makeExample('template-syntax/ts/src/app/app.component.html', 'attribute-binding-syntax-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'attribute-binding-syntax-1')(format=".")
tr
td Class
td.
<code>class</code> Property
td
+makeExample('template-syntax/ts/src/app/app.component.html', 'class-binding-syntax-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'class-binding-syntax-1')(format=".")
tr
td Style
td.
<code>style</code> Property
td
+makeExample('template-syntax/ts/src/app/app.component.html', 'style-binding-syntax-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'style-binding-syntax-1')(format=".")
</div>
:marked
### Spelling target names
.alert.is-critical.
These are current rules. New rules will apply as of alpha 49
:marked
The target name whether between punctuation or after a prefix -
should be spelled with **lowercase**. Although we can spell it in mixed-case,
Angular sees it only after it has been forced to lowercase.
Thats a problem when we need to reference a property with a mixed-case name.
HTML elements have many mixed-case properties: `innerHTML`, `textContent`, `className` to name a few.
Our custom elements (e.g., `<hero-detail>`) may have mixed-case property names
(`HeroDetailComponent.isActive`).
Well be tempted to write bindings that target such properties in mixed-case:
+makeExample('template-syntax/ts/src/app/app.component.html', 'bad-mixed-case')(format=".")
:marked
Try it and the entire display goes blank. A debugger reveals the error:
code-example(format="", language="html").
Template parse errors:
Can't bind to 'textcontent' since it isn't a known native property in ...
:marked
Notice that it forced mixed-case "text**C**ontent" to lowercase "text**c**ontent".
The solution is to write the target property name in **lower kebab-case** (aka *dash-case*),
all lowercase with a dash before each former uppercase letter. We can correct the example as follows:
+makeExample('template-syntax/ts/src/app/app.component.html', 'kebab-case')(format=".")
.l-sub-section
:marked
@ -371,34 +344,34 @@ code-example(format="", language="html").
The most common Property Binding sets an element property to a component property value as when
we bind the source property of an image element to the components `heroImageUrl` property.
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-1')(format=".")
:marked
… or disable a button when the component says that it `isUnchanged`.
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-2')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-2')(format=".")
:marked
… or set a property of a directive
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-3')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-3')(format=".")
:marked
… or set the model property of a custom component (a great way
for parent and child components to communicate)
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-4')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-4')(format=".")
:marked
People often describe Property Binding as “one way data binding” because it can flow a value in one direction, from a components data property to an element property.
### Binding Target
A name between enclosing square brackets identifies the target property. The target property in this example is the image elements `src` property.
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-1')(format=".")
:marked
Some developers prefer the `bind-` prefix alternative, known as the “canonical form”:
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-5')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-5')(format=".")
:marked
The target name is always the name of a property, even when it appears to be the name of something else. We see `src` and may think its the name of an attribute. No. Its the name of an image element property.
Element properties may be the more common targets,
but Angular looks first to see if the name is a property of a known directive
as it is in the following example:
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-3')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-3')(format=".")
.l-sub-section
:marked
@ -419,11 +392,11 @@ code-example(format="", language="html").
The template expression should evaluate to a value of the type expected by the target property. Most native element properties do expect a string. The image `src` should be set to a string, an URL for the resource providing the image. On the other hand, the `disabled` property of a button expects a Boolean value so our expression should evaluate to `true` or `false`.
The `hero` property of the `HeroDetail` component expects a `Hero` object which is exactly what were sending in the Property Binding:
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-4')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-4')(format=".")
:marked
This is good news for the Angular developer.
If `hero` were an attribute we could not set it to a `Hero` object.
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-6')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-6')(format=".")
:marked
We can't set an attribute to an object. We can only set it to a string.
Internally, the attribute may be able to convert that string to an object before setting the like-named element property.
@ -435,7 +408,7 @@ code-example(format="", language="html").
### Property Binding or Interpolation?
We often have a choice between Interpolation and Property Binding. The following binding pairs do the same thing
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-v-interpolation')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-vs-interpolation')(format=".")
:marked
Interpolation is actually a convenient alternative for Property Binding in many cases.
In fact, Angular translates those Interpolations into the corresponding Property Bindings
@ -471,7 +444,7 @@ code-example(format="", language="html").
We become painfull aware of this fact when we try to write something like this:
code-example(language="html").
&lt;tr>&lt;td colspan="{{1+1}}">Three-Four&lt;/td>&lt;/tr>
&lt;tr>&lt;td colspan="{{1 + 1}}">Three-Four&lt;/td>&lt;/tr>
:marked
… and get the error:
code-example(format="", language="html").
@ -489,7 +462,7 @@ code-example(format="", language="html").
followed by the name of the attribute and then set it with an expression that resolves to a string.
Here we bind `[attr.colspan]` to a calulated value:
+makeExample('template-syntax/ts/src/app/app.component.html', 'attrib-binding-colspan')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'attrib-binding-colspan')(format=".")
:marked
Here's how the table renders:
<table border="1px">
@ -499,7 +472,7 @@ code-example(format="", language="html").
One of the primary use cases for the Attribute Binding
is to set aria attributes as we see in this example
+makeExample('template-syntax/ts/src/app/app.component.html', 'attrib-binding-aria')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'attrib-binding-aria')(format=".")
:marked
### Class Binding
@ -511,20 +484,20 @@ code-example(format="", language="html").
In the following examples we see how to add and remove the application's "special" class
with class bindings. We start by setting the attribute without binding:
+makeExample('template-syntax/ts/src/app/app.component.html', 'class-binding-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'class-binding-1')(format=".")
:marked
We replace that with a binding to a string of the desired class names; this is an all-or-nothing, replacement binding.
+makeExample('template-syntax/ts/src/app/app.component.html', 'class-binding-2')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'class-binding-2')(format=".")
:marked
Finally, we bind to a specific class name.
Angular adds the class when the template expression evaluates to something truthy and
removes the class name when the expression is falsey.
+makeExample('template-syntax/ts/src/app/app.component.html', 'class-binding-3')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'class-binding-3')(format=".")
.l-sub-section
:marked
While this is a fine way to toggle a single class name,
we generally prefer the [NgClass directive](#ng-class) for managing multiple class names at the same time.
we generally prefer the [NgClass directive](#ngClass) for managing multiple class names at the same time.
:marked
### Style Binding
@ -535,15 +508,15 @@ code-example(format="", language="html").
Instead of an element property between brackets, we start with the key word `style`
followed by the name of a CSS style property: `[style.style-property]`.
+makeExample('template-syntax/ts/src/app/app.component.html', 'style-binding-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'style-binding-1')(format=".")
:marked
Some Style Binding styles have unit extension. Here we conditionally set the `font-size` in “em” and “%” units .
+makeExample('template-syntax/ts/src/app/app.component.html', 'style-binding-2')(format=".")
Some Style Binding styles have unit extension. Here we conditionally set the `fontSize` in “em” and “%” units .
+makeExample('template-syntax/ts/app/app.component.html', 'style-binding-2')(format=".")
.l-sub-section
:marked
While this is a fine way to set a single style,
we generally prefer the [NgStyle directive](#ng-style) when setting several inline styles at the same time.
we generally prefer the [NgStyle directive](#ngStyle) when setting several inline styles at the same time.
.l-main-section
:marked
@ -559,20 +532,20 @@ code-example(format="", language="html").
We declare our interest in user actions through Angular Event Binding.
The following Event Binding listens for the buttons click event and calls the component's `onSave()` method:
+makeExample('template-syntax/ts/src/app/app.component.html', 'event-binding-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-1')(format=".")
:marked
Event Binding syntax consists of a target event on the left of an equal sign and a template expression on the right: `(click)="onSave()"`
### Binding target
A **name between enclosing parentheses** identifies the target event. In the following example, the target is the buttons click event.
+makeExample('template-syntax/ts/src/app/app.component.html', 'event-binding-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-1')(format=".")
:marked
Some developers prefer the `on-` prefix alternative, known as the “canonical form”:
+makeExample('template-syntax/ts/src/app/app.component.html', 'event-binding-2')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-2')(format=".")
:marked
Element events may be the more common targets, but Angular looks first to see if the name matches an event property
of a known directive as it does in the following example:
+makeExample('template-syntax/ts/src/app/app.component.html', 'event-binding-3')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-3')(format=".")
:marked
If the name fails to match an element event or an output property of a known directive,
Angular reports an “unknown directive” error.
@ -593,7 +566,7 @@ code-example(format="", language="html").
[DOM event object]( https://developer.mozilla.org/en-US/docs/Web/Events) with properties such as `target` and `target.value`.
Consider this example:
+makeExample('template-syntax/ts/src/app/app.component.html', 'without-NgModel')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'without-NgModel')(format=".")
:marked
Were binding the input box `value` to a `firstName` property and were listening for changes by binding to the input boxs `input` event.
When the user makes changes, the `input` event is raised, and the binding executes the expression within a context that includes the DOM event object, `$event`.
@ -602,12 +575,12 @@ code-example(format="", language="html").
If the event belongs to a directive (remember: components are directives), `$event` has whatever shape the directive chose to produce.
Consider a `HeroDetailComponent` that produces `deleted` events with an `EventEmitter`.
+makeExample('template-syntax/ts/src/app/hero-detail.component.ts', 'deleted', 'HeroDetailComponent.ts (excerpt)')(format=".")
+makeExample('template-syntax/ts/app/hero-detail.component.ts', 'deleted', 'HeroDetailComponent.ts (excerpt)')(format=".")
:marked
When something invokes the `onDeleted()` method, we "emit" a `Hero` object.
Now imagine a parent component that listens for that event with an Event Binding.
+makeExample('template-syntax/ts/src/app/app.component.html', 'event-binding-to-component')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-to-component')(format=".")
:marked
The event binding surfaces the *hero-to-delete* emitted by `HeroDetail` to the expression via the `$hero` variable.
We pass it along to the parent `onHeroDeleted()` method.
@ -622,7 +595,7 @@ code-example(format="", language="html").
### Event bubbling and propagation
Angular invokes the event-handling expression if the event is raised by the current element or one of its child elements.
+makeExample('template-syntax/ts/src/app/app.component.html', 'event-binding-bubbling')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-bubbling')(format=".")
:marked
Many DOM events, both [native](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Overview_of_Events_and_Handlers ) and [custom](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events ), “bubble” events up their ancestor tree of DOM elements until an event handler along the way prevents further propagation.
@ -638,65 +611,65 @@ code-example(format="", language="html").
Event propagation stops if the binding expression returns a falsey value (as does a method with no return value).
Clicking the button in this next example triggers a save;
the click doesn't make it to the outer `<div>` so it's save is not called:
+makeExample('template-syntax/ts/src/app/app.component.html', 'event-binding-no-propagation')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-no-propagation')(format=".")
:marked
Propagation continues if the expression returns a truthy value. The click is heard both by the button
and the outer `<div>`, causing a double save:
+makeExample('template-syntax/ts/src/app/app.component.html', 'event-binding-propagation')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-propagation')(format=".")
.l-main-section
:marked
<a name="ng-model"></a>
<a name="ngModel"></a>
## Two-Way Binding with NgModel
When developing data entry forms we often want to both display a data property and update that property when the user makes changes.
The `NgModel` directive serves that purpose as seen in this example:
+makeExample('template-syntax/ts/src/app/app.component.html', 'NgModel-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-1')(format=".")
:marked
If we prefer the “canonical” prefix form to the punctuation form, we can write
+makeExample('template-syntax/ts/src/app/app.component.html', 'NgModel-2')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-2')(format=".")
:marked
Theres a story behind this construction, a story that builds on the Property and Event Binding techniques we learned previously.
We could have achieved the same result as `NgModel` with separate bindings to the
the `<input>` element's `value` property and `input` event.
+makeExample('template-syntax/ts/src/app/app.component.html', 'without-NgModel')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'without-NgModel')(format=".")
:marked
Thats cumbersome. Who can remember what element property to set and what event reports user changes?
How do we extract the currently displayed text from the input box so we can update the data property?
Who wants to look that up each time?
That `ng-model` directive hides these onerous details. It wraps the elements `value` property, listens to the `input` event,
That `ngModel` directive hides these onerous details. It wraps the elements `value` property, listens to the `input` event,
and raises its own event with the changed text ready for us to consume.
+makeExample('template-syntax/ts/src/app/app.component.html', 'NgModel-3')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-3')(format=".")
:marked
Thats an improvement. It should be better.
We shouldn't have to mention the data property twice. Angular should be able to read the components data property and set it
with a single declaration &mdash; which it can with the `[{ }]` syntax:
+makeExample('template-syntax/ts/src/app/app.component.html', 'NgModel-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-1')(format=".")
.l-sub-section
:marked
Internally, Angular maps the term, `ng-model`, to an `ng-model` input property and an
`ng-model-change` output property.
Internally, Angular maps the term, `ngModel`, to an `ngModel` input property and an
`ngModelChange` output property.
Thats a specific example of a more general pattern in which it matches `[(x)]` to an `x` input property
for Property Binding and an `x-change` output property for Event Binding.
We can write our own two-way binding directive that follows this pattern if we're ever in the mood to do so.
:marked
Is `[{ng-model}]` all we need? Is there ever a reason to fall back to its expanded form?
Is `[{ngModel}]` all we need? Is there ever a reason to fall back to its expanded form?
Well `NgModel` can only set the target property.
What if we need to do something more or something different when the user changes the value?
Let's try something silly like forcing the input value to uppercase.
+makeExample('template-syntax/ts/src/app/app.component.html', 'NgModel-4')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-4')(format=".")
:marked
Here are all variations in action, including the uppercase version:
figure.image-display
img(src='/resources/images/devguide/template-syntax/ng-model-anim.gif' alt="NgModel variations")
img(src='/resources/images/devguide/template-syntax/ngModel-anim.gif' alt="NgModel variations")
:marked
.l-main-section
@ -710,7 +683,7 @@ figure.image-display
We dont need many of those directives in Angular 2.
Quite often we can achieve the same results with the more capable and expressive Angular 2 binding system.
Why create a directive to handle a click when we can write a simple binding such as this?
+makeExample('template-syntax/ts/src/app/app.component.html', 'event-binding-2')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-2')(format=".")
:marked
We still benefit from directives that simplify complex tasks.
Angular still ships with built-in directives; just not as many.
@ -718,7 +691,7 @@ figure.image-display
In this segment we review some of the most frequently used built-in directivest.
<a id="ng-class"></a>
<a id="ngClass"></a>
.l-main-section
:marked
### NgClass
@ -728,7 +701,7 @@ figure.image-display
We can bind to `NgClass` to add or remove several classes simultaneously.
We prefer to use a [Class Binding](#class-binding) to add or remove a *single* class.
+makeExample('template-syntax/ts/src/app/app.component.html', 'class-binding-3a')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'class-binding-3a')(format=".")
:marked
The `NgClass` directive may be the better choice
when we want to add or remove *many* classes at the same time.
@ -736,12 +709,12 @@ figure.image-display
Our favorite way to apply `NgClass` is by binding it to a key:value control object. Each key of the object is a class name and its value is `true` if the class should be added, `false` if it should be removed.
Consider a component method such as `setClasses` that returns its approval of two class names:
+makeExample('template-syntax/ts/src/app/app.component.ts', 'setClasses')(format=".")
+makeExample('template-syntax/ts/app/app.component.ts', 'setClasses')(format=".")
:marked
Now add an `NgClass` property binding to call it like this
+makeExample('template-syntax/ts/src/app/app.component.html', 'NgClass-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'NgClass-1')(format=".")
<a id="ng-style"></a>
<a id="ngStyle"></a>
.l-main-section
:marked
### NgStyle
@ -749,7 +722,7 @@ figure.image-display
We bind to `NgStyle` to set many inline styles simultaneously.
We prefer to use a [Style Binding](#style-binding) to set a *single* style value.
+makeExample('template-syntax/ts/src/app/app.component.html', 'NgStyle-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'NgStyle-1')(format=".")
:marked
The `NgStyle` directive may be the better choice
when we want to set *many* inline styles at the same time.
@ -758,29 +731,29 @@ figure.image-display
Each key of the object is a style name and its value is whatever is appropriate for that style.
Consider a component method such as `setStyles` that returns an object defining three styles:
+makeExample('template-syntax/ts/src/app/app.component.ts', 'setStyles')(format=".")
+makeExample('template-syntax/ts/app/app.component.ts', 'setStyles')(format=".")
:marked
Now add an `NgStyle` property binding to call it like this
+makeExample('template-syntax/ts/src/app/app.component.html', 'NgStyle-2')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'NgStyle-2')(format=".")
<a id="ng-if"></a>
<a id="ngIf"></a>
.l-main-section
:marked
### NgIf
We can add an element sub-tree (an element and its children) to the DOM by binding an `NgIf` directive to a truthy expression.
+makeExample('template-syntax/ts/src/app/app.component.html', 'NgIf-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'NgIf-1')(format=".")
.alert.is-critical
:marked
The leading asterisk (\*) in front of `ng-if` is a critical part of this syntax.
The leading asterisk (\*) in front of `ngIf` is a critical part of this syntax.
See the section below on [\* and &lt;template>](#star-template).
:marked
Binding to a falsey expression removes the element sub-tree from the DOM.
+makeExample('template-syntax/ts/src/app/app.component.html', 'NgIf-2')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'NgIf-2')(format=".")
:marked
#### Visibility and NgIf are not the same
We can show and hide an element sub-tree (the element and its children) with a [Class](#class-binding) or a [Style](#style-binding) binding:
+makeExample('template-syntax/ts/src/app/app.component.html', 'NgIf-3')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'NgIf-3')(format=".")
:marked
Hiding a sub-tree is quite different from excluding a sub-tree with `NgIf`.
@ -796,7 +769,7 @@ figure.image-display
The show/hide technique is probably fine for small element trees.
We should be wary when hiding large trees; `NgIf` may be the safer choice. Always measure before leaping to conclusions.
<a id="ng-switch"></a>
<a id="ngSwitch"></a>
.l-main-section
:marked
### NgSwitch
@ -805,7 +778,7 @@ figure.image-display
Angular only puts the *selected* element tree into the DOM.
Heres an example:
+makeExample('template-syntax/ts/src/app/app.component.html', 'NgSwitch')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'NgSwitch')(format=".")
:marked
We bind the parent `NgSwitch` element to an expression returning a “switch value”. The value is a string in this example but it can be a value of any type.
@ -816,11 +789,11 @@ figure.image-display
If the templates “match value” equals the “switch value”, Angular adds the templates sub-tree to the DOM. If no template is a match and there is a default template, Angular adds the default templates sub-tree to the DOM. Angular removes and destroys the sub-trees of all other templates.
There are three related directives at work here.
1. `ng-switch` - bound to an expression that returns the switch value.
1. `ng-switch-when` - bound to an expression returning a match value.
1. `ng-switch-default` - a marker attribute on the default template.
1. `ngSwitch` - bound to an expression that returns the switch value.
1. `ngSwitchWhen` - bound to an expression returning a match value.
1. `ngSwitchDefault` - a marker attribute on the default template.
<a id="ng-for"></a>
<a id="ngFor"></a>
.l-main-section
:marked
### NgFor
@ -830,22 +803,22 @@ figure.image-display
We tell Angular to use that block as a template for rendering each item in the list.
Here is an example of `NgFor` applied to a simple `<div>`.
+makeExample('template-syntax/ts/src/app/app.component.html', 'NgFor-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'NgFor-1')(format=".")
:marked
We can apply an `NgFor` to a component element as well as we do in this example:
+makeExample('template-syntax/ts/src/app/app.component.html', 'NgFor-2')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'NgFor-2')(format=".")
.alert.is-critical
:marked
The leading asterisk (\*) in front of `ng-for` is a critical part of this syntax.
The leading asterisk (\*) in front of `ngFor` is a critical part of this syntax.
See the section below on [\* and &lt;template>](#star-template).
:marked
The text assigned to `*ng-for` is the instruction that guides the repeater process.
The text assigned to `*ngFor` is the instruction that guides the repeater process.
.l-sub-section
:marked
#### NgFor Micro-syntax
The string assigned to `*ng-for` is not a [template expression](#template-expressions).
The string assigned to `*ngFor` is not a [template expression](#template-expressions).
Its a little language of its own called a “micro-syntax” that Angular interprets. In this example it means:
>*Take each hero in the `heroes` array, store it in the local `hero` variable, and make it available to the templated HTML
@ -854,7 +827,7 @@ figure.image-display
Angular translates this instruction into a new set of elements and bindings.
Well talk about this in the next section about templates.
:marked
In our two examples, the `ng-for` directive iterates over the `heroes` array returned by the parent components `heroes` property
In our two examples, the `ngFor` directive iterates over the `heroes` array returned by the parent components `heroes` property
and stamps out instances of the element to which it is applied.
Angular creates a fresh instance of the template for each hero in the array.
@ -864,12 +837,12 @@ figure.image-display
or we can pass it in a binding to a component element as we're doing with `hero-detail`.
#### NgFor with index
The `ng-for` directive supports an optional index that increases from 0 to the length of the array for each iteration.
The `ngFor` directive supports an optional index that increases from 0 to the length of the array for each iteration.
We can capture that in another local template variable (`i`) and use it in our template too.
This next example stamps out rows that display like "1 - Hercules Son of Zeus":
+makeExample('template-syntax/ts/src/app/app.component.html', 'NgFor-3')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'NgFor-3')(format=".")
:marked
<a name="star-template"></a>
@ -877,31 +850,31 @@ figure.image-display
.l-main-section
:marked
## * and &lt;template>
When we reviewed the `ng-for` and `ng-if` built-in directives we called out an oddity of the syntax, the asterisk (*) that appears before the directive name.
When we reviewed the `ngFor` and `ngIf` built-in directives we called out an oddity of the syntax, the asterisk (*) that appears before the directive name.
This is a bit of “**syntactic sugar**” that makes it easier to read and write directives that modify HTML layout
with the help of templates.
`NgFor`, `NgIf`, and `NgSwitch` all add and remove element subtrees that are wrapped in `<template>` tags.
With the [NgSwitch](#ng-switch) directive we always write the `<template>` tags explicitly as we saw [above](#ng-switch).
With the [NgSwitch](#ngSwitch) directive we always write the `<template>` tags explicitly as we saw [above](#ngSwitch).
There isnt much choice; we define a different template for each switch choice
and let the directive render the template that matches the switch value.
[NgFor](#ng-for) and [NgIf](#ng-if) only need one template,
[NgFor](#ngFor) and [NgIf](#ngIf) only need one template,
the *template-to-repeat* and the *template-to-include* respectively.
The (\*) prefix syntax is a convenient way for developers to skip the `<template>` wrapper tags and
focus directly on the HTML element to repeat or include.
Angular sees the (*) and expands the HTML into the `<template>` tags for us.
### Expanding `*ng-if`
### Expanding `*ngIf`
We can do that ourselves if we wish. Instead of writing ...
+makeExample('template-syntax/ts/src/app/app.component.html', 'Template-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'Template-1')(format=".")
:marked
… we can write:
+makeExample('template-syntax/ts/src/app/app.component.html', 'Template-2')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'Template-2')(format=".")
:marked
Notice the (\*) is gone and we have a [Property Binding](#property-binding) to the `ng-if`
Notice the (\*) is gone and we have a [Property Binding](#property-binding) to the `ngIf`
directive, applied in this case to the `<template>` rather than
the applications `hero-detail` component.
@ -912,26 +885,26 @@ figure.image-display
.callout.is-critical
header Remember the brackets!
:marked
Dont make the mistake of writing `ng-if="currentHero"`!
That syntax assigns the *string* value, "currentHero", to `ng-if`.
In JavaScript a non-empty string is a truthy value so `ng-if` would always be
Dont make the mistake of writing `ngIf="currentHero"`!
That syntax assigns the *string* value, "currentHero", to `ngIf`.
In JavaScript a non-empty string is a truthy value so `ngIf` would always be
`true` and Angular will always display the `hero-detail`
… even when there is no `currentHero`!
:marked
### Expanding `*ng-for`
A similar transformation applies to `*ng-for`. We can "de-sugar" the syntax ourselves and go from ...
+makeExample('template-syntax/ts/src/app/app.component.html', 'NgFor-2')(format=".")
### Expanding `*ngFor`
A similar transformation applies to `*ngFor`. We can "de-sugar" the syntax ourselves and go from ...
+makeExample('template-syntax/ts/app/app.component.html', 'NgFor-2')(format=".")
:marked
... to
+makeExample('template-syntax/ts/src/app/app.component.html', 'Template-3')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'Template-3')(format=".")
:marked
... and from there to
+makeExample('template-syntax/ts/src/app/app.component.html', 'Template-4')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'Template-4')(format=".")
:marked
This is a bit more complex than `NgIf` because a repeater has more moving parts to configure.
In this case, we have to remember the `NgForOf` directive that identifies the list.
It should be clear why we prefer the `*ng-for` syntax to writing out this expanded HTML ourselves.
It should be clear why we prefer the `*ngFor` syntax to writing out this expanded HTML ourselves.
<a id="local-vars"></a>
.l-main-section
@ -941,11 +914,11 @@ figure.image-display
A **local template variable** is a vehicle for moving data across element lines.
We've seen the `#hero` local template variable several times in this chapter,
most prominently when writing [NgFor](#ng-for) repeaters.
most prominently when writing [NgFor](#ngFor) repeaters.
In the [* and &lt;templates>](#star-template) segment we learned how Angular expands
an `*ng-for` on a component tag into a `<template>` that wraps the component.
+makeExample('template-syntax/ts/src/app/app.component.html', 'Template-4')(format=".")
an `*ngFor` on a component tag into a `<template>` that wraps the component.
+makeExample('template-syntax/ts/app/app.component.html', 'Template-4')(format=".")
:marked
The (#) prefix character in front of "hero" means that we're defining a `hero` variable.
.l-sub-section
@ -965,7 +938,7 @@ figure.image-display
any of its child elements.
Here are two other examples of creating and consuming a local template variable:
+makeExample('template-syntax/ts/src/app/app.component.html', 'var-phone')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'var-phone')(format=".")
:marked
### How it gets its value
The value assigned to the variable depends upon the context.
@ -985,11 +958,11 @@ figure.image-display
The HTML for a form can be quite involved as we saw in the [Forms](forms.html) chapter.
The following is a *simplified* example &mdash; and it's not simple at all.
+makeExample('template-syntax/ts/src/app/app.component.html', 'var-form')
+makeExample('template-syntax/ts/app/app.component.html', 'var-form')
:marked
A local template variable, `theForm`, appears three times in this example, separated
by a large amount of HTML.
+makeExample('template-syntax/ts/src/app/app.component.html', 'var-form-a')
+makeExample('template-syntax/ts/app/app.component.html', 'var-form-a')
:marked
What is the value of `theForm`?
@ -1031,12 +1004,12 @@ figure.image-display
In the following example, `iconUrl` and `onSave` are members of the `AppComponent`
referenced within template expressions to the *right* of the (=).
+makeExample('template-syntax/ts/src/app/app.component.html', 'io-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'io-1')(format=".")
:marked
They are *neither inputs nor outputs* of `AppComponent`. They are data sources for their bindings.
Now look at the `HeroDetailComponent` when it is the **target of a binding**.
+makeExample('template-syntax/ts/src/app/app.component.html', 'io-2')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'io-2')(format=".")
:marked
Both `HeroDetail.hero` and `HeroDetail.deleted` are on the **left side** of binding expressions.
`HeroDetail.hero` is the target of a Property Binding. `HeroDetail.deleted` is the target of an Event Binding.
@ -1050,13 +1023,13 @@ figure.image-display
When we peek inside `HeroDetailComponent` we see that these properties are marked
with decorators as input and output properties.
+makeExample('template-syntax/ts/src/app/hero-detail.component.ts', 'input-output-1')(format=".")
+makeExample('template-syntax/ts/app/hero-detail.component.ts', 'input-output-1')(format=".")
:marked
.l-sub-section
:marked
Alternatively, we can identify them in the `inputs` and `outputs` arrays
of the directive metadata as seen in this example:
+makeExample('template-syntax/ts/src/app/hero-detail.component.ts', 'input-output-2')(format=".")
+makeExample('template-syntax/ts/app/hero-detail.component.ts', 'input-output-2')(format=".")
<br>
:marked
We can specify an input/output property with a decorator or in one the metadata arrays &mdash; but not both.
@ -1075,12 +1048,12 @@ figure.image-display
Fortunately, we can alias the internal name to meet the conventional needs of the directive's consumer.
We alias in decorator syntax like this:
+makeExample('template-syntax/ts/src/app/my-click.directive.ts', 'my-click-output-1')(format=".")
+makeExample('template-syntax/ts/app/my-click.directive.ts', 'my-click-output-1')(format=".")
.l-sub-section
:marked
The equivalent aliasing with the `outputs` array requires a colon-delimited string with
the internal property name on the left and the public name on the right:
+makeExample('template-syntax/ts/src/app/my-click.directive.ts', 'my-click-output-2')(format=".")
+makeExample('template-syntax/ts/app/my-click.directive.ts', 'my-click-output-2')(format=".")
<a id="expression-operators"></a>
.l-main-section
@ -1096,30 +1069,30 @@ figure.image-display
Angular [Pipes](./pipes.html) are a good choice for small transformations such as these.
Pipes are simple functions that accept an input value and return a transformed value.
They are easy to apply within template expressions using the **pipe operator ( | )**:
+makeExample('template-syntax/ts/src/app/app.component.html', 'pipes-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'pipes-1')(format=".")
:marked
The pipe operator passes the result of an expression on the left to a pipe function on the right.
We can chain expressions through multiple pipes
+makeExample('template-syntax/ts/src/app/app.component.html', 'pipes-2')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'pipes-2')(format=".")
:marked
And we can configure them too:
+makeExample('template-syntax/ts/src/app/app.component.html', 'pipes-3')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'pipes-3')(format=".")
:marked
The `json` pipe is particular helpful for debugging our bindings:
+makeExample('template-syntax/ts/src/app/app.component.html', 'pipes-json')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'pipes-json')(format=".")
:marked
<a id="elvis"></a>
### The Elvis Operator ( ?. ) and null property paths
The Angular **“Elvis” operator ( ?. )** is a fluent and convenient way to guard against null and undefined values in property paths.
Here it is, protecting against a view render failure if the `currentHero` is null.
+makeExample('template-syntax/ts/src/app/app.component.html', 'elvis-2')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-2')(format=".")
:marked
Lets elaborate on the problem and this particular solution.
What happens when the following data bound `title` property is null?
+makeExample('template-syntax/ts/src/app/app.component.html', 'elvis-1')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-1')(format=".")
:marked
The view still renders but the displayed value is blank; we see only "`The title is`" with nothing after it.
That is reasonable behavior. At least the app doesn't crash.
@ -1149,12 +1122,12 @@ code-example(format="" language="html").
Unfortunately, our app crashes when the `currentHero` is null.
We could code around that problem with [NgIf](#ng-if)
+makeExample('template-syntax/ts/src/app/app.component.html', 'elvis-4')(format=".")
We could code around that problem with [NgIf](#ngIf)
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-4')(format=".")
:marked
Or we could try to chain parts of the property path with `&&`, knowing that the expression bails out
when it encounters the first null.
+makeExample('template-syntax/ts/src/app/app.component.html', 'elvis-5')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-5')(format=".")
:marked
These approaches have merit but they can be cumbersome, especially if the property path is long.
Imagine guarding against a null somewhere in a long property path such as `a.b.c.d`.
@ -1162,7 +1135,7 @@ code-example(format="" language="html").
The Angular **“Elvis” operator ( ?. )** is a more fluent and convenient way to guard against nulls in property paths.
The expression bails out when it hits the first null value.
The display is blank but the app keeps rolling and there are no errors.
+makeExample('template-syntax/ts/src/app/app.component.html', 'elvis-6')(format=".")
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-6')(format=".")
:marked
It works perfectly with long property paths too:
```