Merge remote-tracking branch 'remotes/angular.io/master'

# Conflicts:
#	public/docs/ts/latest/guide/template-syntax.jade
This commit is contained in:
Zhimin(Rex) YE 2016-05-26 23:48:22 +01:00
commit cbea511cad
23 changed files with 971 additions and 1300 deletions

24
.travis.yml Normal file
View File

@ -0,0 +1,24 @@
dist: trusty
sudo: required
language: node_js
node_js:
- "5"
os:
- linux
env:
global:
- DISPLAY=:99.0
- CHROME_BIN=chromium-browser
matrix:
- SCRIPT="run-e2e-tests --fast"
before_install:
- npm install -g gulp --no-optional
before_script:
- sh -e /etc/init.d/xvfb start
install:
- npm install --no-optional
- npm install --prefix public/docs/_examples
- npm run webdriver:update --prefix public/docs/_examples
- gulp add-example-boilerplate
script:
- gulp $SCRIPT

View File

@ -60,7 +60,7 @@ var _devguideShredJadeOptions = {
}; };
var _apiShredOptions = { var _apiShredOptions = {
examplesDir: path.join(ANGULAR_PROJECT_PATH, 'modules/angular2/examples'), examplesDir: path.join(ANGULAR_PROJECT_PATH, 'modules/@angular/examples'),
fragmentsDir: path.join(DOCS_PATH, '_fragments/_api'), fragmentsDir: path.join(DOCS_PATH, '_fragments/_api'),
zipDir: path.join(RESOURCES_PATH, 'zips/api') zipDir: path.join(RESOURCES_PATH, 'zips/api')
}; };
@ -103,9 +103,6 @@ var _exampleDartWebBoilerPlateFiles = ['styles.css'];
* all means (ts|js|dart) * all means (ts|js|dart)
*/ */
gulp.task('run-e2e-tests', function() { gulp.task('run-e2e-tests', function() {
var exePath = path.join(process.cwd(), "./node_modules/.bin/");
var promise; var promise;
if (argv.fast) { if (argv.fast) {
// fast; skip all setup // fast; skip all setup
@ -115,7 +112,7 @@ gulp.task('run-e2e-tests', function() {
var spawnInfo = spawnExt('npm', ['install'], { cwd: EXAMPLES_PATH}); var spawnInfo = spawnExt('npm', ['install'], { cwd: EXAMPLES_PATH});
promise = spawnInfo.promise.then(function() { promise = spawnInfo.promise.then(function() {
copyExampleBoilerplate(); copyExampleBoilerplate();
spawnInfo = spawnExt('webdriver-manager', ['update'], {cwd: exePath}); spawnInfo = spawnExt('npm', ['run', 'webdriver:update'], {cwd: EXAMPLES_PATH});
return spawnInfo.promise; return spawnInfo.promise;
}); });
} }
@ -124,9 +121,12 @@ gulp.task('run-e2e-tests', function() {
return findAndRunE2eTests(argv.filter); return findAndRunE2eTests(argv.filter);
}).then(function(status) { }).then(function(status) {
reportStatus(status); reportStatus(status);
if (status.failed.length > 0){
return Promise.reject('Some test suites failed');
}
}).catch(function(e) { }).catch(function(e) {
gutil.log(e); gutil.log(e);
return e; process.exit(1);
}); });
}); });
@ -213,9 +213,8 @@ function runProtractor(prepPromise, appDir, appRunSpawnInfo, protractorConfigFil
.then(function (data) { .then(function (data) {
// start protractor // start protractor
var pcFilename = path.resolve(protractorConfigFilename); // need to resolve because we are going to be running from a different dir var pcFilename = path.resolve(protractorConfigFilename); // need to resolve because we are going to be running from a different dir
var exePath = path.join(process.cwd(), "./node_modules/.bin/"); var spawnInfo = spawnExt('npm', [ 'run', 'protractor', '--', pcFilename,
var spawnInfo = spawnExt('protractor', '--params.appDir=' + appDir, '--params.outputFile=' + outputFile], { cwd: EXAMPLES_PATH });
[ pcFilename, '--params.appDir=' + appDir, '--params.outputFile=' + outputFile], { cwd: exePath });
return spawnInfo.promise return spawnInfo.promise
}) })
.then( .then(
@ -483,9 +482,14 @@ gulp.task('git-changed-examples', ['_shred-devguide-examples'], function(){
gulp.task('check-deploy', ['build-docs'], function() { gulp.task('check-deploy', ['build-docs'], function() {
return harpCompile().then(function() { return harpCompile().then(function() {
gutil.log('compile ok - running live server ...'); gutil.log('compile ok');
execPromise('npm run live-server ./www'); if(argv.dryRun) {
return askDeploy(); return false;
} else {
gutil.log('running live server ...');
execPromise('npm run live-server ./www');
return askDeploy();
}
}).then(function(shouldDeploy) { }).then(function(shouldDeploy) {
if (shouldDeploy) { if (shouldDeploy) {
gutil.log('deploying...'); gutil.log('deploying...');
@ -847,7 +851,7 @@ function filterOutExcludedPatterns(fileNames, excludeMatchers) {
} }
function apiSourceWatch(postBuildAction) { function apiSourceWatch(postBuildAction) {
var srcPattern = [path.join(ANGULAR_PROJECT_PATH, 'modules/angular2/src/**/*.*')]; var srcPattern = [path.join(ANGULAR_PROJECT_PATH, 'modules/@angular/src/**/*.*')];
gulp.watch(srcPattern, {readDelay: 500}, function (event, done) { gulp.watch(srcPattern, {readDelay: 500}, function (event, done) {
gutil.log('API source changed'); gutil.log('API source changed');
gutil.log('Event type: ' + event.event); // added, changed, or deleted gutil.log('Event type: ' + event.event); // added, changed, or deleted
@ -858,7 +862,7 @@ function apiSourceWatch(postBuildAction) {
} }
function apiExamplesWatch(postShredAction) { function apiExamplesWatch(postShredAction) {
var examplesPath = path.join(ANGULAR_PROJECT_PATH, 'modules/angular2/examples/**'); var examplesPath = path.join(ANGULAR_PROJECT_PATH, 'modules/@angular/examples/**');
var includePattern = path.join(examplesPath, '**/*.*'); var includePattern = path.join(examplesPath, '**/*.*');
var excludePattern = '!' + path.join(examplesPath, '**/node_modules/**/*.*'); var excludePattern = '!' + path.join(examplesPath, '**/node_modules/**/*.*');
var cleanPath = [path.join(_apiShredOptions.fragmentsDir, '**/*.*'), '!**/*.ovr.*']; var cleanPath = [path.join(_apiShredOptions.fragmentsDir, '**/*.*'), '!**/*.ovr.*'];

View File

@ -22,6 +22,7 @@
- var _an = 'an'; - var _an = 'an';
//- TS arrays vs. Dart lists //- TS arrays vs. Dart lists
- var _Array = 'Array';
- var _array = 'array'; - var _array = 'array';
//- Deprecate now that we have the articles _a and _an //- Deprecate now that we have the articles _a and _an
- var _an_array = 'an array'; - var _an_array = 'an array';
@ -33,6 +34,9 @@
//- Location of sample code //- Location of sample code
- var _liveLink = 'live link'; - var _liveLink = 'live link';
//- Other
- var _truthy = 'truthy';
- var _falsey = 'falsey';
//- Used to prefix identifiers that are private. In Dart this will be '_'. //- Used to prefix identifiers that are private. In Dart this will be '_'.
- var _priv = ''; - var _priv = '';
@ -40,8 +44,8 @@
//- Use to conditionally include the block that follows +ifDocsFor(...). //- Use to conditionally include the block that follows +ifDocsFor(...).
//- Generally favor use of Jade named blocks instead. ifDocsFor is convenient //- Generally favor use of Jade named blocks instead. ifDocsFor is convenient
//- for prose that should appear only in one language version. //- for prose that should appear only in one language version.
mixin ifDocsFor(lang) mixin ifDocsFor(langPattern)
if _docsFor.toLowerCase() === lang.toLowerCase() if _docsFor.toLowerCase().match(langPattern.toLowerCase())
block block
//- Use to map inlined (prose) TS paths into, say, Dart paths via the //- Use to map inlined (prose) TS paths into, say, Dart paths via the

View File

@ -13,6 +13,7 @@
"tsc": "tsc", "tsc": "tsc",
"tsc:w": "tsc -w", "tsc:w": "tsc -w",
"typings": "typings", "typings": "typings",
"protractor": "protractor",
"webdriver:update": "webdriver-manager update", "webdriver:update": "webdriver-manager update",
"start:webpack": "webpack-dev-server --inline --progress --port 8080", "start:webpack": "webpack-dev-server --inline --progress --port 8080",
"test:webpack": "karma start karma.webpack.conf.js", "test:webpack": "karma start karma.webpack.conf.js",

View File

@ -59,7 +59,7 @@ describe('Router', function () {
crisisCenterEdit(2, true); crisisCenterEdit(2, true);
}); });
it('should be able to edit and cancel details from the crisis center view', function () { xit('should be able to edit and cancel details from the crisis center view', function () {
crisisCenterEdit(3, false); crisisCenterEdit(3, false);
}); });

View File

@ -3,6 +3,7 @@ import 'dart:convert';
import 'dart:html'; import 'dart:html';
import 'package:angular2/core.dart'; import 'package:angular2/core.dart';
import 'package:angular2/common.dart';
import 'hero.dart'; import 'hero.dart';
import 'hero_detail_component.dart'; import 'hero_detail_component.dart';
@ -40,7 +41,9 @@ class AppComponent implements OnInit, AfterViewInit {
bool isSpecial = true; bool isSpecial = true;
bool isUnchanged = true; bool isUnchanged = true;
bool isSelected = false; bool isSelected = false;
final Color colorRed = Color.red;
Color color = Color.red; Color color = Color.red;
var colorEnum = Color;
List<Hero> heroes; List<Hero> heroes;
Hero currentHero; Hero currentHero;
@ -56,7 +59,7 @@ class AppComponent implements OnInit, AfterViewInit {
final Hero nullHero = null; final Hero nullHero = null;
Map product = {'name': 'frimfram', 'price': 42}; Map product = {'name': 'frimfram', 'price': 42};
FormElement form; FormElement form;
String clickity = ''; String clicked = '';
String clickMessage = ''; String clickMessage = '';
String clickMessage2 = ''; String clickMessage2 = '';
final String iconUrl = 'assets/images/ng-logo.png'; final String iconUrl = 'assets/images/ng-logo.png';
@ -87,14 +90,14 @@ class AppComponent implements OnInit, AfterViewInit {
int getVal() => val; int getVal() => val;
void onCancel(MouseEvent event) { void onCancel(UIEvent event) {
DivElement el = event.target; HtmlElement el = event?.target;
var evtMsg = event != null ? 'Event target is ${el.innerHtml}.' : ''; var evtMsg = event != null ? 'Event target is ${el.innerHtml}.' : '';
alerter('Canceled. $evtMsg'); alerter('Canceled. $evtMsg');
} }
void onClickMe(MouseEvent event) { void onClickMe(UIEvent event) {
DivElement el = event.target; HtmlElement el = event?.target;
var evtMsg = event != null ? 'Event target class is ${el.className}.' : ''; var evtMsg = event != null ? 'Event target class is ${el.className}.' : '';
alerter('Click me. $evtMsg'); alerter('Click me. $evtMsg');
} }
@ -103,9 +106,10 @@ class AppComponent implements OnInit, AfterViewInit {
alerter('Deleted hero: ${hero?.firstName}'); alerter('Deleted hero: ${hero?.firstName}');
} }
bool onSave([MouseEvent event = null]) { bool onSave([UIEvent event = null]) {
HtmlElement el = event?.target;
var evtMsg = var evtMsg =
event != null ? ' Event target is ${event.target.innerHtml}.' : ''; event != null ? ' Event target is ${el.innerHtml}.' : '';
alerter('Saved. $evtMsg'); alerter('Saved. $evtMsg');
return false; return false;
} }

View File

@ -31,11 +31,11 @@
</div> </div>
<br> <br>
<a href="#star-prefix">* prefix and &lt;template&gt;</a><br> <a href="#star-prefix">* prefix and &lt;template&gt;</a><br>
<a href="#local-vars">Template local variables</a><br> <a href="#ref-vars">Template reference variables</a><br>
<a href="#inputs-and-outputs">Inputs and outputs</a><br> <a href="#inputs-and-outputs">Inputs and outputs</a><br>
<a href="#pipes">Pipes</a><br> <a href="#pipes">Pipes</a><br>
<a href="#safe-navigation-operator">Safe navigation operator <i>?.</i></a><br> <a href="#safe-navigation-operator">Safe navigation operator <i>?.</i></a><br>
<!--<a href="#enums">Enums</a><br>--> <a href="#enums">Enums</a><br>
<!-- Interpolation and expressions --> <!-- Interpolation and expressions -->
<hr><h2 id="interpolation">Interpolation</h2> <hr><h2 id="interpolation">Interpolation</h2>
@ -105,9 +105,9 @@
<!-- #docregion event-binding-syntax-1 --> <!-- #docregion event-binding-syntax-1 -->
<button (click) = "onSave()">Save</button> <button (click) = "onSave()">Save</button>
<hero-detail (deleteRequest)="deleteHero()"></hero-detail> <hero-detail (deleteRequest)="deleteHero()"></hero-detail>
<div (myClick)="clickity=$event">click me</div> <div (myClick)="clicked=$event">click me</div>
<!-- #enddocregion event-binding-syntax-1 --> <!-- #enddocregion event-binding-syntax-1 -->
{{clickity}} {{clicked}}
<br><br> <br><br>
<div> <div>
@ -184,15 +184,14 @@ button</button>
<!-- #enddocregion property-binding-5 --> <!-- #enddocregion property-binding-5 -->
<!-- #docregion property-binding-6 --> <!-- #docregion property-binding-6 -->
<!-- BAD! HeroDetailComponent.hero expects a Hero object, <!-- ERROR: HeroDetailComponent.hero expects a
not the string "currentHero". Hero object, not the string "currentHero" -->
<hero-detail hero="currentHero"></hero-detail> -->
<!-- #enddocregion property-binding-6 --> <!-- #enddocregion property-binding-6 -->
<div *ngIf="false">
<!-- In checked mode, uncommenting the hero-detail above causes this: <!-- #docregion property-binding-6 -->
EXCEPTION: type 'String' is not a subtype of type 'Hero' of 'value'. --> <hero-detail hero="currentHero"></hero-detail>
<!-- #enddocregion property-binding-6 -->
</div>
<!-- #docregion property-binding-7 --> <!-- #docregion property-binding-7 -->
<hero-detail prefix="You are my" [hero]="currentHero"></hero-detail> <hero-detail prefix="You are my" [hero]="currentHero"></hero-detail>
<!-- #enddocregion property-binding-7 --> <!-- #enddocregion property-binding-7 -->
@ -202,7 +201,7 @@ Interpolated: <img src="{{heroImageUrl}}"><br>
Property bound: <img [src]="heroImageUrl"> Property bound: <img [src]="heroImageUrl">
<div>The interpolated title is {{title}}</div> <div>The interpolated title is {{title}}</div>
<div [textContent]="'The [textContent] title is '+title"></div> <div [innerHTML]="'The [innerHTML] title is '+title"></div>
<!-- #enddocregion property-binding-vs-interpolation --> <!-- #enddocregion property-binding-vs-interpolation -->
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>
@ -258,9 +257,7 @@ Property bound: <img [src]="heroImageUrl">
<!-- #docregion class-binding-2 --> <!-- #docregion class-binding-2 -->
<!-- reset/override all class names with a binding --> <!-- reset/override all class names with a binding -->
<div class="bad curly special" <div class="bad curly special"
[class]="badCurly">Bad curly</div> [className]="badCurly">Bad curly</div>
<p><b>Note:</b> "Bad curly" should be smaller but isn't, due to
<a href="http://github.com/angular/angular/issues/6901">issue #6901</a>.</p>
<!-- #enddocregion class-binding-2 --> <!-- #enddocregion class-binding-2 -->
<!-- #docregion class-binding-3 --> <!-- #docregion class-binding-3 -->
@ -374,15 +371,15 @@ bindon-ngModel
<br> <br>
<!-- #docregion NgModel-3 --> <!-- #docregion NgModel-3 -->
<input <input
[ngModel]="currentHero.firstName" [ngModel]="currentHero.firstName"
(ngModelChange)="currentHero.firstName=$event"> (ngModelChange)="currentHero.firstName=$event">
<!-- #enddocregion NgModel-3 --> <!-- #enddocregion NgModel-3 -->
(ngModelChange) = "...firstName=$event" (ngModelChange) = "...firstName=$event"
<br> <br>
<!-- #docregion NgModel-4 --> <!-- #docregion NgModel-4 -->
<input <input
[ngModel]="currentHero.firstName" [ngModel]="currentHero.firstName"
(ngModelChange)="setUpperCaseFirstName($event)"> (ngModelChange)="setUpperCaseFirstName($event)">
<!-- #enddocregion NgModel-4 --> <!-- #enddocregion NgModel-4 -->
(ngModelChange) = "setUpperCaseFirstName($event)" (ngModelChange) = "setUpperCaseFirstName($event)"
<br> <br>
@ -443,7 +440,7 @@ bindon-ngModel
<!-- #enddocregion NgIf-1 --> <!-- #enddocregion NgIf-1 -->
<!-- #docregion NgIf-2 --> <!-- #docregion NgIf-2 -->
<!-- not displayed because nullHero is false. <!-- because of the ngIf guard
`nullHero.firstName` never has a chance to fail --> `nullHero.firstName` never has a chance to fail -->
<div *ngIf="nullHero != null">Hello, {{nullHero.firstName}}</div> <div *ngIf="nullHero != null">Hello, {{nullHero.firstName}}</div>
@ -487,33 +484,33 @@ bindon-ngModel
</fieldset> </fieldset>
<div class="toe"> <div class="toe">
<div *ngIf="toeChoice == null">Pick a toe</div> <div *ngIf="toeChoice == null">Pick a toe</div>
<div *ngIf="toeChoice != null"> <div *ngIf="toeChoice != null">
You picked ... You picked ...
<!-- #docregion NgSwitch, NgSwitch-expanded --> <!-- #docregion NgSwitch, NgSwitch-expanded -->
<span [ngSwitch]="toeChoice"> <span [ngSwitch]="toeChoice">
<!-- #enddocregion NgSwitch --> <!-- #enddocregion NgSwitch -->
<!-- with *NgSwitch --> <!-- with *NgSwitch -->
<!-- #docregion NgSwitch --> <!-- #docregion NgSwitch -->
<span *ngSwitchWhen="'Eenie'">Eenie</span> <span *ngSwitchWhen="'Eenie'">Eenie</span>
<span *ngSwitchWhen="'Meanie'">Meanie</span> <span *ngSwitchWhen="'Meanie'">Meanie</span>
<span *ngSwitchWhen="'Miney'">Miney</span> <span *ngSwitchWhen="'Miney'">Miney</span>
<span *ngSwitchWhen="'Moe'">Moe</span> <span *ngSwitchWhen="'Moe'">Moe</span>
<span *ngSwitchDefault>other</span> <span *ngSwitchDefault>other</span>
<!-- #enddocregion NgSwitch --> <!-- #enddocregion NgSwitch -->
<!-- with <template> --> <!-- with <template> -->
<template ngSwitchWhen="Eenie"><span>Eenie</span></template> <template [ngSwitchWhen]="'Eenie'"><span>Eenie</span></template>
<template ngSwitchWhen="Meanie"><span>Meanie</span></template> <template [ngSwitchWhen]="'Meanie'"><span>Meanie</span></template>
<template ngSwitchWhen="Miney"><span>Miney</span></template> <template [ngSwitchWhen]="'Miney'"><span>Miney</span></template>
<template ngSwitchWhen="Moe"><span>Moe</span></template> <template [ngSwitchWhen]="'Moe'"><span>Moe</span></template>
<template ngSwitchDefault><span>other</span></template> <template ngSwitchDefault><span>other</span></template>
<!-- #docregion NgSwitch --> <!-- #docregion NgSwitch -->
</span> </span>
<!-- #enddocregion NgSwitch, NgSwitch-expanded --> <!-- #enddocregion NgSwitch, NgSwitch-expanded -->
</div> </div>
</div> </div>
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>
@ -620,7 +617,7 @@ bindon-ngModel
<p><i>expand to &lt;template&gt;</i></p> <p><i>expand to &lt;template&gt;</i></p>
<!-- #docregion Template-2 --> <!-- #docregion Template-2 -->
<template [ngIf]="currentHero != null"> <template [ngIf]="currentHero != null">
<hero-detail [hero]="currentHero"></hero-detail> <hero-detail [hero]="currentHero"></hero-detail>
</template> </template>
<!-- #enddocregion Template-2 --> <!-- #enddocregion Template-2 -->
@ -644,15 +641,15 @@ bindon-ngModel
<!-- ngFor w/ hero-detail Component inside a template element --> <!-- ngFor w/ hero-detail Component inside a template element -->
<!-- #docregion Template-4 --> <!-- #docregion Template-4 -->
<template ngFor let-hero [ngForOf]="heroes" [ngForTrackBy]="trackByHeroes"> <template ngFor let-hero [ngForOf]="heroes" [ngForTrackBy]="trackByHeroes">
<hero-detail [hero]="hero"></hero-detail> <hero-detail [hero]="hero"></hero-detail>
</template> </template>
<!-- #enddocregion Template-4 --> <!-- #enddocregion Template-4 -->
</div> </div>
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>
<!-- template local variable --> <!-- template reference variable -->
<hr><h2 id="local-vars">Template local variables</h2> <hr><h2 id="ref-vars">Template reference variables</h2>
<!-- #docregion ref-phone --> <!-- #docregion ref-phone -->
<!-- phone refers to the input element; pass its `value` to an event handler --> <!-- phone refers to the input element; pass its `value` to an event handler -->
@ -672,7 +669,7 @@ bindon-ngModel
<div class="form-group"> <div class="form-group">
<label for="name">Name</label> <label for="name">Name</label>
<input class="form-control" required ngControl="firstName" <input class="form-control" required ngControl="firstName"
[(ngModel)]="currentHero.firstName"> [(ngModel)]="currentHero.firstName">
</div> </div>
<!-- #docregion ref-form-a --> <!-- #docregion ref-form-a -->
<button type="submit" [disabled]="!theForm.form.valid">Submit</button> <button type="submit" [disabled]="!theForm.form.valid">Submit</button>
@ -682,7 +679,7 @@ bindon-ngModel
<br><br> <br><br>
<!-- btn refers to the button element; show its disabled state --> <!-- btn refers to the button element; show its disabled state -->
<button #btn disabled [textContent]="'disabled by attribute: ' + btn.disabled.toString()"></button> <button #btn disabled [innerHTML]="'disabled by attribute: ' + btn.disabled.toString()"></button>
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>
@ -708,13 +705,15 @@ bindon-ngModel
<hr><h2 id="pipes">Pipes</h2> <hr><h2 id="pipes">Pipes</h2>
<!-- #docregion pipes-1 --> <!-- #docregion pipes-1 -->
<!-- Force title to uppercase --> <div>Title through uppercase pipe: {{title | uppercase}}</div>
<div>{{ title | uppercase }}</div>
<!-- #enddocregion pipes-1 --> <!-- #enddocregion pipes-1 -->
<!-- #docregion pipes-2 --> <!-- #docregion pipes-2 -->
<!-- Pipe chaining: force title to uppercase, then to lowercase --> <!-- Pipe chaining: convert title to uppercase, then to lowercase -->
<div>{{ title | uppercase | lowercase }}</div> <div>
Title through a pipe chain:
{{title | uppercase | lowercase}}
</div>
<!-- #enddocregion pipes-2 --> <!-- #enddocregion pipes-2 -->
<!-- #docregion pipes-3 --> <!-- #docregion pipes-3 -->
@ -723,16 +722,14 @@ bindon-ngModel
<!-- #enddocregion pipes-3 --> <!-- #enddocregion pipes-3 -->
<!-- #docregion pipes-json --> <!-- #docregion pipes-json -->
<!-- We don't suggest using json for debugging; you'd probably use toString() instead. <div>{{currentHero}}</div>
Is there a good use for the json pipe in Dart? -->
<!--<div>{{currentHero | json}}</div>-->
<!-- #enddocregion pipes-json --> <!-- #enddocregion pipes-json -->
<div>Birthdate: {{(currentHero?.birthdate | date:'longDate') | uppercase}}</div> <div>Birthdate: {{(currentHero?.birthdate | date:'longDate') | uppercase}}</div>
<div> <div>
<!-- pipe price to USD and display the $ symbol --> <!-- pipe price to USD and display the $ symbol -->
<label>Price: </label>{{product['price'] | currency:'$'}} <label>Price: </label>{{product['price'] | currency:'USD':false}}
</div> </div>
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>
@ -742,7 +739,7 @@ bindon-ngModel
<div> <div>
<!-- #docregion safe-1 --> <!-- #docregion safe-1 -->
The title is {{ title }} The title is {{title}}
<!-- #enddocregion safe-1 --> <!-- #enddocregion safe-1 -->
</div> </div>
@ -759,11 +756,10 @@ bindon-ngModel
</div> </div>
<!-- <!--
The null hero's name is {{nullHero.firstName}} The null hero's name is {{nullHero.firstName}}
See console log: See console log:
EXCEPTION: The null object does not have a getter 'firstName'. EXCEPTION: The null object does not have a getter 'firstName'.
--> -->
@ -784,19 +780,16 @@ The null hero's name is {{nullHero.firstName}}
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>
<!-- Todo: discuss this in the Style binding section --> <!-- TODO: discuss this in the Style binding section -->
<!-- enums in bindings --> <!-- enums in bindings -->
<hr><h2 id="enums">Enums in binding</h2> <hr><h2 id="enums">Enums in binding</h2>
<!--<p>The name of the Color.red enum is {{color}}</p>--> <p>
<p>The current color number is {{color}}</p> <!-- #docregion enums -->
<p><button [style.color]="color.toString()" (click)="colorToggle()">Enum Toggle</button> The name of the Color.red enum is {{colorRed}}.<br>
The current color is {{color}} and its index is {{color.index}}.<br>
<a class="to-toc" href="#toc">top</a> <button [style.color]="color.toString()" (click)="colorToggle()">Enum Toggle</button>
<!-- #enddocregion enums -->
<!-- #docregion my-first-app --> </p>
<h3>My First Angular Application</h3>
<!-- #enddocregion my-first-app -->
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>

View File

@ -52,13 +52,13 @@
<!-- #enddocregion title+image --> <!-- #enddocregion title+image -->
<!-- #docregion sum-1 --> <!-- #docregion sum-1 -->
<!-- "The sum of 1 + 1 is 2" --> <!-- "The sum of 1 + 1 is 2" -->
<p>The sum of 1 + 1 is {{1 + 1}}</p> <p>The sum of 1 + 1 is {{1 + 1}}</p>
<!-- #enddocregion sum-1 --> <!-- #enddocregion sum-1 -->
<!-- #docregion sum-2 --> <!-- #docregion sum-2 -->
<!-- "The sum of 1 + 1 is not 4" --> <!-- "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 --> <!-- #enddocregion sum-2 -->
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>
@ -66,8 +66,8 @@
<!-- New Mental Model --> <!-- New Mental Model -->
<hr><h2 id="mental-model">New Mental Model</h2> <hr><h2 id="mental-model">New Mental Model</h2>
<!--<img src="http://www.wpclipart.com/cartoon/people/hero/hero_silhoutte_T.png">--> <!--<img src="http://www.wpclipart.com/cartoon/people/hero/hero_silhoutte_T.png">-->
<!-- Public Domain terms of use: http://www.wpclipart.com/terms.html --> <!-- Public Domain terms of use: http://www.wpclipart.com/terms.html -->
<!-- #docregion img+button --> <!-- #docregion img+button -->
<div class="special">Mental Model</div> <div class="special">Mental Model</div>
<img src="images/hero.png"> <img src="images/hero.png">
@ -184,13 +184,14 @@ button</button>
<!-- #enddocregion property-binding-5 --> <!-- #enddocregion property-binding-5 -->
<!-- #docregion property-binding-6 --> <!-- #docregion property-binding-6 -->
<!-- <!-- ERROR: HeroDetailComponent.hero expects a
BAD! Hero object, not the string "currentHero" -->
HeroDetailComponent.hero expects a Hero object,
not the string "currentHero"
-->
<hero-detail hero="currentHero"></hero-detail>
<!-- #enddocregion property-binding-6 --> <!-- #enddocregion property-binding-6 -->
<div *ngIf="false">
<!-- #docregion property-binding-6 -->
<hero-detail hero="currentHero"></hero-detail>
<!-- #enddocregion property-binding-6 -->
</div>
<!-- #docregion property-binding-7 --> <!-- #docregion property-binding-7 -->
<hero-detail prefix="You are my" [hero]="currentHero"></hero-detail> <hero-detail prefix="You are my" [hero]="currentHero"></hero-detail>
<!-- #enddocregion property-binding-7 --> <!-- #enddocregion property-binding-7 -->
@ -199,8 +200,8 @@ button</button>
Interpolated: <img src="{{heroImageUrl}}"><br> Interpolated: <img src="{{heroImageUrl}}"><br>
Property bound: <img [src]="heroImageUrl"> Property bound: <img [src]="heroImageUrl">
<div>The interpolated title is {{title}}</div> <div>The interpolated title is {{title}}</div>
<div [innerHTML]="'The [innerHTML] title is '+title"></div> <div [innerHTML]="'The [innerHTML] title is '+title"></div>
<!-- #enddocregion property-binding-vs-interpolation --> <!-- #enddocregion property-binding-vs-interpolation -->
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>
@ -278,13 +279,13 @@ Property bound: <img [src]="heroImageUrl">
<hr><h2 id="style-binding">Style Binding</h2> <hr><h2 id="style-binding">Style Binding</h2>
<!-- #docregion style-binding-1 --> <!-- #docregion style-binding-1 -->
<button [style.color] = "isSpecial ? 'red' : 'green'">Red</button> <button [style.color] = "isSpecial ? 'red': 'green'">Red</button>
<button [style.backgroundColor]="canSave ?'cyan' : 'grey'" >Save</button> <button [style.background-color]="canSave ? 'cyan': 'grey'" >Save</button>
<!-- #enddocregion style-binding-1 --> <!-- #enddocregion style-binding-1 -->
<!-- #docregion style-binding-2 --> <!-- #docregion style-binding-2 -->
<button [style.fontSize.em]="isSpecial ? 3 : 1" >Big</button> <button [style.font-size.em]="isSpecial ? 3 : 1" >Big</button>
<button [style.fontSize.%]="!isSpecial ? 150 : 50" >Small</button> <button [style.font-size.%]="!isSpecial ? 150 : 50" >Small</button>
<!-- #enddocregion style-binding-2 --> <!-- #enddocregion style-binding-2 -->
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>
@ -393,7 +394,7 @@ bindon-ngModel
<div [ngClass]="setClasses()">This div is saveable and special</div> <div [ngClass]="setClasses()">This div is saveable and special</div>
<!-- #enddocregion NgClass-1 --> <!-- #enddocregion NgClass-1 -->
<div [ngClass]="setClasses()" #classDiv> <div [ngClass]="setClasses()" #classDiv>
After setClasses(), the classes are "{{classDiv.className}}" After setClasses(), the classes are "{{classDiv.className}}"
</div> </div>
<!-- not used in chapter --> <!-- not used in chapter -->
@ -409,8 +410,8 @@ After setClasses(), the classes are "{{classDiv.className}}"
<hr><h2 id="ngStyle">NgStyle Binding</h2> <hr><h2 id="ngStyle">NgStyle Binding</h2>
<!-- #docregion NgStyle-1 --> <!-- #docregion NgStyle-1 -->
<div [style.fontSize]="isSpecial ? 'x-large' : 'smaller'" > <div [style.font-size]="isSpecial ? 'x-large' : 'smaller'" >
This div is x-large This div is x-large.
</div> </div>
<!-- #enddocregion NgStyle-1 --> <!-- #enddocregion NgStyle-1 -->
@ -418,12 +419,12 @@ After setClasses(), the classes are "{{classDiv.className}}"
<p>setStyles returns {{setStyles() | json}}</p> <p>setStyles returns {{setStyles() | json}}</p>
<!-- #docregion NgStyle-2 --> <!-- #docregion NgStyle-2 -->
<div [ngStyle]="setStyles()"> <div [ngStyle]="setStyles()">
This div is italic, normal weight, and extra large (24px) This div is italic, normal weight, and extra large (24px).
</div> </div>
<!-- #enddocregion NgStyle-2 --> <!-- #enddocregion NgStyle-2 -->
<p>After setStyles(), the DOM confirms that the styles are <p>After setStyles(), the DOM confirms that the styles are
<span [ngStyle]="setStyles()" #styleDiv> <span [ngStyle]="setStyles()" #styleDiv>
"{{getStyles(styleDiv)}}" {{getStyles(styleDiv)}}
</span>. </span>.
</p> </p>
@ -439,7 +440,7 @@ After setClasses(), the classes are "{{classDiv.className}}"
<!-- #enddocregion NgIf-1 --> <!-- #enddocregion NgIf-1 -->
<!-- #docregion NgIf-2 --> <!-- #docregion NgIf-2 -->
<!-- not displayed because nullHero is falsey. <!-- because of the ngIf guard
`nullHero.firstName` never has a chance to fail --> `nullHero.firstName` never has a chance to fail -->
<div *ngIf="nullHero">Hello, {{nullHero.firstName}}</div> <div *ngIf="nullHero">Hello, {{nullHero.firstName}}</div>
@ -603,22 +604,22 @@ After setClasses(), the classes are "{{classDiv.className}}"
<hr><h2 id="star-prefix">* prefix and &lt;template&gt;</h2> <hr><h2 id="star-prefix">* prefix and &lt;template&gt;</h2>
<h3>*ngIf expansion</h3> <h3>*ngIf expansion</h3>
<p><i>*ngIf</i></p> <p><i>*ngIf</i></p>
<!-- #docregion Template-1 --> <!-- #docregion Template-1 -->
<hero-detail *ngIf="currentHero" [hero]="currentHero"></hero-detail> <hero-detail *ngIf="currentHero" [hero]="currentHero"></hero-detail>
<!-- #enddocregion Template-1 --> <!-- #enddocregion Template-1 -->
<p><i>expand to template = "..."</i></p> <p><i>expand to template = "..."</i></p>
<!-- #docregion Template-2a --> <!-- #docregion Template-2a -->
<hero-detail template="ngIf:currentHero" [hero]="currentHero"></hero-detail> <hero-detail template="ngIf:currentHero" [hero]="currentHero"></hero-detail>
<!-- #enddocregion Template-2a --> <!-- #enddocregion Template-2a -->
<p><i>expand to &lt;template&gt;</i></p> <p><i>expand to &lt;template&gt;</i></p>
<!-- #docregion Template-2 --> <!-- #docregion Template-2 -->
<template [ngIf]="currentHero"> <template [ngIf]="currentHero">
<hero-detail [hero]="currentHero"></hero-detail> <hero-detail [hero]="currentHero"></hero-detail>
</template> </template>
<!-- #enddocregion Template-2 --> <!-- #enddocregion Template-2 -->
<h3>*ngFor expansion</h3> <h3>*ngFor expansion</h3>
<p><i>*ngFor</i></p> <p><i>*ngFor</i></p>
@ -658,7 +659,7 @@ After setClasses(), the classes are "{{classDiv.className}}"
<!-- fax refers to the input element; pass its `value` to an event handler --> <!-- fax refers to the input element; pass its `value` to an event handler -->
<input ref-fax placeholder="fax number"> <input ref-fax placeholder="fax number">
<button (click)="callFax(fax.value)">Fax</button> <button (click)="callFax(fax.value)">Fax</button>
<!-- #enddocregion ref-phone --> <!-- #enddocregion ref-phone -->
<h4>Example Form</h4> <h4>Example Form</h4>
<!-- #docregion ref-form --> <!-- #docregion ref-form -->
@ -704,13 +705,15 @@ After setClasses(), the classes are "{{classDiv.className}}"
<hr><h2 id="pipes">Pipes</h2> <hr><h2 id="pipes">Pipes</h2>
<!-- #docregion pipes-1 --> <!-- #docregion pipes-1 -->
<!-- Force title to uppercase --> <div>Title through uppercase pipe: {{title | uppercase}}</div>
<div>{{ title | uppercase }}</div>
<!-- #enddocregion pipes-1 --> <!-- #enddocregion pipes-1 -->
<!-- #docregion pipes-2 --> <!-- #docregion pipes-2 -->
<!-- Pipe chaining: force title to uppercase, then to lowercase --> <!-- Pipe chaining: convert title to uppercase, then to lowercase -->
<div>{{ title | uppercase | lowercase }}</div> <div>
Title through a pipe chain:
{{title | uppercase | lowercase}}
</div>
<!-- #enddocregion pipes-2 --> <!-- #enddocregion pipes-2 -->
<!-- #docregion pipes-3 --> <!-- #docregion pipes-3 -->
@ -720,16 +723,8 @@ After setClasses(), the classes are "{{classDiv.className}}"
<!-- #docregion pipes-json --> <!-- #docregion pipes-json -->
<div>{{currentHero | json}}</div> <div>{{currentHero | json}}</div>
<!-- Output:
{ "firstName": "Hercules", "lastName": "Son of Zeus",
"birthdate": "1970-02-25T08:00:00.000Z",
"url": "http://www.imdb.com/title/tt0065832/",
"rate": 325, "id": 1 }
-->
<!-- #enddocregion pipes-json --> <!-- #enddocregion pipes-json -->
<div>Birthdate: {{(currentHero?.birthdate | date:'longDate') | uppercase}}</div> <div>Birthdate: {{(currentHero?.birthdate | date:'longDate') | uppercase}}</div>
<div> <div>
@ -743,29 +738,29 @@ After setClasses(), the classes are "{{classDiv.className}}"
<hr><h2 id="safe-navigation-operator">Safe navigation operator <i>?.</i></h2> <hr><h2 id="safe-navigation-operator">Safe navigation operator <i>?.</i></h2>
<div> <div>
<!-- #docregion safe-1 --> <!-- #docregion safe-1 -->
The title is {{ title }} The title is {{title}}
<!-- #enddocregion safe-1 --> <!-- #enddocregion safe-1 -->
</div> </div>
<div> <div>
<!-- #docregion safe-2 --> <!-- #docregion safe-2 -->
The current hero's name is {{currentHero?.firstName}} The current hero's name is {{currentHero?.firstName}}
<!-- #enddocregion safe-2 --> <!-- #enddocregion safe-2 -->
</div> </div>
<div> <div>
<!-- #docregion safe-3 --> <!-- #docregion safe-3 -->
The current hero's name is {{currentHero.firstName}} The current hero's name is {{currentHero.firstName}}
<!-- #enddocregion safe-3 --> <!-- #enddocregion safe-3 -->
</div> </div>
<!-- <!--
The null hero's name is {{nullHero.firstName}} The null hero's name is {{nullHero.firstName}}
See console log See console log:
TypeError: Cannot read property 'firstName' of null in [null] TypeError: Cannot read property 'firstName' of null in [null]
--> -->
<!-- #docregion safe-4 --> <!-- #docregion safe-4 -->
@ -780,27 +775,25 @@ The null hero's name is {{nullHero && nullHero.firstName}}
</div> </div>
<div> <div>
<!-- #docregion safe-6 --> <!-- #docregion safe-6 -->
<!-- No hero, no problem! --> <!-- No hero, no problem! -->
The null hero's name is {{nullHero?.firstName}} The null hero's name is {{nullHero?.firstName}}
<!-- #enddocregion safe-6 --> <!-- #enddocregion safe-6 -->
</div> </div>
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>
<!-- Todo: discuss this in the Style binding section --> <!-- TODO: discuss this in the Style binding section -->
<!-- enums in bindings --> <!-- enums in bindings -->
<hr><h2 id="enums">Enums in binding</h2> <hr><h2 id="enums">Enums in binding</h2>
<p>The name of the Color.Red enum is {{Color[Color.Red]}}</p> <p>
<p>The current color number is {{color}}</p> <!-- #docregion enums -->
<p><button [style.color]="Color[color]" (click)="colorToggle()">Enum Toggle</button> The name of the Color.Red enum is {{Color[Color.Red]}}.<br>
The current color is {{Color[color]}} and its number is {{color}}.<br>
<a class="to-toc" href="#toc">top</a> <button [style.color]="Color[color]" (click)="colorToggle()">Enum Toggle</button>
<!-- #enddocregion enums -->
<!-- #docregion my-first-app --> </p>
<h3>My First Angular Application</h3>
<!-- #enddocregion my-first-app -->
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>

View File

@ -77,6 +77,9 @@ export class AppComponent implements AfterViewInit, OnInit {
heroImageUrl = 'images/hero.png'; heroImageUrl = 'images/hero.png';
//iconUrl = 'https://angular.io/resources/images/logos/standard/shield-large.png'; //iconUrl = 'https://angular.io/resources/images/logos/standard/shield-large.png';
clicked = '';
clickMessage = '';
clickMessage2 = '';
iconUrl = 'images/ng-logo.png'; iconUrl = 'images/ng-logo.png';
isActive = false; isActive = false;
isSpecial = true; isSpecial = true;

View File

@ -1,4 +1,4 @@
import { Hero } from '../Hero'; import { Hero } from '../hero';
export class MainController { export class MainController {
hero = new Hero(1, 'Windstorm', 'Specific powers of controlling winds'); hero = new Hero(1, 'Windstorm', 'Specific powers of controlling winds');

View File

@ -1,7 +1,7 @@
// #docregion // #docregion
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { upgradeAdapter } from './upgrade_adapter'; import { upgradeAdapter } from './upgrade_adapter';
import { Hero } from '../Hero'; import { Hero } from '../hero';
const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail'); const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail');

View File

@ -1,4 +1,4 @@
import { Hero } from '../Hero'; import { Hero } from '../hero';
export class MainController { export class MainController {
hero = new Hero(1, 'Windstorm'); hero = new Hero(1, 'Windstorm');

View File

@ -1,7 +1,7 @@
// #docregion // #docregion
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { upgradeAdapter } from './upgrade_adapter'; import { upgradeAdapter } from './upgrade_adapter';
import { Hero } from '../Hero'; import { Hero } from '../hero';
const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail'); const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail');

View File

@ -25,7 +25,7 @@ html(lang="en" ng-app="angularIOApp" itemscope itemtype="http://schema.org/Frame
else else
article(class="l-content-small grid-fluid docs-content") article(class="l-content-small grid-fluid docs-content")
div(class="c10") div(class="c10")
.showcase.shadow-1 .showcase
.showcase-content .showcase-content
!= yield != yield
if (current.path[3] == 'guide' || current.path[3] == 'tutorial') && current.path[4] if (current.path[3] == 'guide' || current.path[3] == 'tutorial') && current.path[4]

View File

@ -3,6 +3,7 @@ include ../../../_includes/_util-fns
//- See the _util-fns file included above for a description of the use of these variables. //- See the _util-fns file included above for a description of the use of these variables.
- var _docsFor = 'dart'; - var _docsFor = 'dart';
- var _decorator = 'annotation'; - var _decorator = 'annotation';
- var _Array = 'List';
- var _array = 'list'; - var _array = 'list';
- var _an_array = 'a list'; //- Deprecate now that we have the articles - var _an_array = 'a list'; //- Deprecate now that we have the articles
- var _a = 'an'; - var _a = 'an';
@ -12,6 +13,8 @@ include ../../../_includes/_util-fns
- var _Promise = 'Future'; - var _Promise = 'Future';
- var _Observable = 'Stream'; - var _Observable = 'Stream';
- var _liveLink = 'sample repo'; - var _liveLink = 'sample repo';
- var _truthy = 'true';
- var _falsey = 'false';
mixin liveExampleLink(linkText, exampleUrlPartName) mixin liveExampleLink(linkText, exampleUrlPartName)
- var text = linkText || '在线例子'; - var text = linkText || '在线例子';
@ -37,7 +40,7 @@ mixin liveExampleLink2(linkText, exampleUrlPartName)
- // Adjust the folder path, e.g., ts -> dart - // Adjust the folder path, e.g., ts -> dart
- folder = folder.replace(/(^|\/)ts($|\/)/, '$1dart$2').replace(/(^|\/)app($|\/)/, inWebFolder ? '$1web$2' : '$1lib$2'); - folder = folder.replace(/(^|\/)ts($|\/)/, '$1dart$2').replace(/(^|\/)app($|\/)/, inWebFolder ? '$1web$2' : '$1lib$2');
- // Special case not handled above: e.g., index.html -> web/index.html - // Special case not handled above: e.g., index.html -> web/index.html
- if(baseNameNoExt.match(/^(index|styles)(\.\d)?$/)) folder = (folder ? folder + '/' : '') + 'web'; - if(baseNameNoExt.match(/^(index|styles)(\.\d)?$/) && !folder.match(/web$/)) folder = (folder ? folder + '/' : '') + 'web';
- // In file name, replace special characters with underscore - // In file name, replace special characters with underscore
- baseNameNoExt = baseNameNoExt.replace(/[\-\.]/g, '_'); - baseNameNoExt = baseNameNoExt.replace(/[\-\.]/g, '_');
- // Adjust the file extension - // Adjust the file extension

View File

@ -1,407 +1,128 @@
include ../_util-fns extends ../../../ts/latest/guide/template-syntax.jade
+includeShared('{ts}', 'intro') block includes
include ../_util-fns
- var _JavaScript = 'Dart';
- var __chaining_op = '<code>;</code>';
- var __new_op = '<code>new</code> or <code>const</code>';
- var mapApiRef = 'https://api.dartlang.org/stable/1.16.0/dart-core/Map-class.html';
- var __objectAsMap = '<b><a href="' + mapApiRef + '">Map</a></b>'
:marked block notable-differences
The complete source code for the example app in this chapter is
[in GitHub](https://github.com/angular/angular.io/tree/master/public/docs/_examples/template-syntax/dart).
+includeShared('{ts}', 'html-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'my-first-app')(format=".")
+includeShared('{ts}', 'html-2')
+includeShared('{ts}', 'interpolation-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'first-interpolation')(format=".")
+includeShared('{ts}', 'interpolation-2')
+makeExample('template-syntax/dart/lib/app_component.html', 'title+image')(format=".")
+includeShared('{ts}', 'interpolation-3')
+makeExample('template-syntax/dart/lib/app_component.html', 'sum-1')(format=".")
+includeShared('{ts}', 'interpolation-4')
+makeExample('template-syntax/dart/lib/app_component.html', 'sum-2')(format=".")
+includeShared('{ts}', 'interpolation-5')
+includeShared('{ts}', 'template-expressions-1')
:marked
We write template expressions in a language that looks like Dart.
Many Dart expressions are legal template expressions, but not all.
Dart expressions that have or promote side effects are prohibited,
including:
* assignments (`=`, `+=`, `-=`, ...)
* creating instances using `new` or `const`
* increment and decrement (`++` and `--`)
Other notable differences from Dart syntax include:
* no support for Dart string interpolation; for example,
instead of `"'The title is $title'"`, you must use
`"'The title is ' + title"`
* no support for the bitwise operators `|` and `&`
* new [template expression operators](#expression-operators), such as `|`
+includeShared('{ts}', 'template-expressions-context')
+includeShared('{ts}', 'template-expressions-guidelines')
:marked
Dependent values should not change during a single turn of the event loop.
If an idempotent expression returns a string or a number, it returns the same string or number
when called twice in a row. If the expression returns an object (including a `DateTime`, `Map`, or `List`),
it returns the same object *reference* when called twice in a row.
.callout.is-helpful
header Dart difference: Arrays are lists
:marked :marked
Arrays in JavaScript correspond to lists in Dart * no support for Dart string interpolation; for example,
(instances of the `List` class). instead of `"'The title is $title'"`, you must use
This chapter uses _array_ and _list_ interchangeably. `"'The title is ' + title"`
For more information, see * no support for the bitwise operators `|` and `&`
[Lists](https://www.dartlang.org/docs/dart-up-and-running/ch02.html#lists) * new [template expression operators](#expression-operators), such as `|`
in the [Dart language tour](https://www.dartlang.org/docs/dart-up-and-running/ch02.html).
+includeShared('{ts}', 'template-statements-1') block template-expressions-cannot
:marked
Like template expressions, template *statements* use a language that looks like Dart.
The template statement parser is different than the template expression parser and
specifically supports both basic assignment (`=`) and chaining expressions with semicolons (`;`).
However, certain Dart syntax is not allowed:
* the `new` and `const` keywords
* increment and decrement operators, `++` and `--`
* operator assignment, such as `+=` and `-=`
* the operators `|` and `&` (neither for bitwise operations
nor for the Angular [pipe operator](#the-pipe-operator-))
+includeShared('{ts}', 'template-statements-3')
+includeShared('{ts}', 'binding-syntax-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'img+button')(format=".")
+includeShared('{ts}', 'binding-syntax-2')
+makeExample('template-syntax/dart/lib/app_component.html', 'hero-detail-1')(format=".")
+includeShared('{ts}', 'binding-syntax-3')
+makeExample('template-syntax/dart/lib/app_component.html', 'disabled-button-1')(format=".")
+includeShared('{ts}', 'binding-syntax-4')
+includeShared('{ts}', 'binding-syntax-attribute-vs-property')
+includeShared('{ts}', 'binding-syntax-5')
+includeShared('{ts}', 'binding-syntax-world-without-attributes')
+includeShared('{ts}', 'binding-syntax-targets')
<div width="90%">
table
tr
th Binding type
th Target
th Examples
tr
td Property
td.
Element&nbsp;property<br>
Component&nbsp;property<br>
Directive&nbsp;property
td
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-syntax-1')(format=".")
tr
td Event
td.
Element&nbsp;event<br>
Component&nbsp;event<br>
Directive&nbsp;event
td
+makeExample('template-syntax/dart/lib/app_component.html', 'event-binding-syntax-1')(format=".")
tr
td Two-way
td.
Event and property
td
+makeExample('template-syntax/dart/lib/app_component.html', '2-way-binding-syntax-1')(format=".")
tr
td Attribute
td.
Attribute
(the&nbsp;exception)
td
+makeExample('template-syntax/dart/lib/app_component.html', 'attribute-binding-syntax-1')(format=".")
tr
td Class
td.
<code>class</code> property
td
+makeExample('template-syntax/dart/lib/app_component.html', 'class-binding-syntax-1')(format=".")
tr
td Style
td.
<code>style</code> property
td
+makeExample('template-syntax/dart/lib/app_component.html', 'style-binding-syntax-1')(format=".")
</div>
+includeShared('{ts}', 'binding-syntax-end')
+includeShared('{ts}', 'property-binding-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-1')(format=".")
+includeShared('{ts}', 'property-binding-2')
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-2')(format=".")
+includeShared('{ts}', 'property-binding-3')
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-3')(format=".")
+includeShared('{ts}', 'property-binding-4')
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-4')(format=".")
+includeShared('{ts}', 'property-binding-5')
+includeShared('{ts}', 'property-binding-6')
+includeShared('{ts}', 'property-binding-7')
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-1')(format=".")
+includeShared('{ts}', 'property-binding-8')
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-5')(format=".")
+includeShared('{ts}', 'property-binding-9')
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-3')(format=".")
+includeShared('{ts}', 'property-binding-10')
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-4')(format=".")
+includeShared('{ts}', 'property-binding-11')
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-6')(format=".")
.callout.is-helpful
header Dart difference: Type exceptions
:marked :marked
In checked mode, uncommenting the `<hero-detail>` element above causes a type exception, Perhaps more surprising, template expressions cant refer to static
because `String` isn't a subtype of `Hero`. properties, nor to top-level variables or functions, such as `window` or
For information on checked mode, see [Important concepts](https://www.dartlang.org/docs/dart-up-and-running/ch02.html#important-concepts) `document` from `dart:html`. They cant directly call `print` or functions
in the Dart language tour. imported from `dart:math`. They are restricted to referencing members of
+includeShared('{ts}', 'property-binding-12') the expression context.
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-7')(format=".")
+includeShared('{ts}', 'property-binding-13')
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-vs-interpolation')(format=".")
+includeShared('{ts}', 'property-binding-14')
+includeShared('{ts}', 'other-bindings-1') block statement-context
+includeShared('{ts}', 'other-bindings-2')
+makeExample('template-syntax/dart/lib/app_component.html', 'attrib-binding-colspan')(format=".")
+includeShared('{ts}', 'other-bindings-3')
+makeExample('template-syntax/dart/lib/app_component.html', 'attrib-binding-aria')(format=".")
+includeShared('{ts}', 'other-bindings-class-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'class-binding-1')(format=".")
+includeShared('{ts}', 'other-bindings-class-2')
+makeExample('template-syntax/dart/lib/app_component.html', 'class-binding-2')(format=".")
//
+includeShared('{ts}', 'other-bindings-class-3')
:marked
Finally, we can bind to a specific class name.
Angular adds the class when the template expression evaluates to `true`.
It removes the class when the expression evaluates to `false`.
+makeExample('template-syntax/dart/lib/app_component.html', 'class-binding-3')(format=".")
+includeShared('{ts}', 'other-bindings-class-4')
+includeShared('{ts}', 'other-bindings-style-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'style-binding-1')(format=".")
+includeShared('{ts}', 'other-bindings-style-2')
+makeExample('template-syntax/dart/lib/app_component.html', 'style-binding-2')(format=".")
+includeShared('{ts}', 'other-bindings-style-3')
+includeShared('{ts}', 'event-binding-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'event-binding-1')(format=".")
+includeShared('{ts}', 'event-binding-2')
+makeExample('template-syntax/dart/lib/app_component.html', 'event-binding-1')(format=".")
+includeShared('{ts}', 'event-binding-3')
+makeExample('template-syntax/dart/lib/app_component.html', 'event-binding-2')(format=".")
+includeShared('{ts}', 'event-binding-4')
+makeExample('template-syntax/dart/lib/app_component.html', 'event-binding-3')(format=".")
+includeShared('{ts}', 'event-binding-5')
+makeExample('template-syntax/dart/lib/app_component.html', 'without-NgModel')(format=".")
+includeShared('{ts}', 'event-binding-6')
+makeExample('template-syntax/dart/lib/hero_detail_component.dart',
'template-1', 'HeroDetailComponent.ts (template)')(format=".")
+makeExample('template-syntax/dart/lib/hero_detail_component.dart',
'deleteRequest', 'HeroDetailComponent.ts (delete logic)')(format=".")
+includeShared('{ts}', 'event-binding-7')
+makeExample('template-syntax/dart/lib/app_component.html', 'event-binding-to-component')(format=".")
+includeShared('{ts}', 'event-binding-8')
+includeShared('{ts}', 'ngModel-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'NgModel-1')(format=".")
+includeShared('{ts}', 'ngModel-2')
+makeExample('template-syntax/dart/lib/app_component.html', 'NgModel-2')(format=".")
+includeShared('{ts}', 'ngModel-3')
+makeExample('template-syntax/dart/lib/app_component.html', 'without-NgModel')(format=".")
+includeShared('{ts}', 'ngModel-4')
+makeExample('template-syntax/dart/lib/app_component.html', 'NgModel-3')(format=".")
+includeShared('{ts}', 'ngModel-5')
+makeExample('template-syntax/dart/lib/app_component.html', 'NgModel-1')(format=".")
+includeShared('{ts}', 'ngModel-6')
+makeExample('template-syntax/dart/lib/app_component.html', 'NgModel-4')(format=".")
+includeShared('{ts}', 'ngModel-7')
+includeShared('{ts}', 'directives-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'event-binding-1')(format=".")
+includeShared('{ts}', 'directives-2')
+includeShared('{ts}', 'directives-ngClass-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'class-binding-3a')(format=".")
+includeShared('{ts}', 'directives-ngClass-2')
+makeExample('template-syntax/dart/lib/app_component.dart', 'setClasses')(format=".")
// PENDING: Add "Dart difference" for returning maps in Dart? for omitting unnecessary `this.`s?
+includeShared('{ts}', 'directives-ngClass-3')
+makeExample('template-syntax/dart/lib/app_component.html', 'NgClass-1')(format=".")
+includeShared('{ts}', 'directives-ngStyle-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'NgStyle-1')(format=".")
+includeShared('{ts}', 'directives-ngStyle-2')
+makeExample('template-syntax/dart/lib/app_component.dart', 'setStyles')(format=".")
+includeShared('{ts}', 'directives-ngStyle-3')
+makeExample('template-syntax/dart/lib/app_component.html', 'NgStyle-2')(format=".")
//
+includeShared('{ts}', 'directives-ngIf-1')
<a id="ngIf"></a>
.l-main-section
:marked
### NgIf
We can add an element subtree (an element and its children) to the DOM by binding an `NgIf` directive to a `true` expression.
+makeExample('template-syntax/dart/lib/app_component.html', 'NgIf-1')(format=".")
+includeShared('{ts}', 'directives-ngIf-2')
//
+includeShared('{ts}', 'directives-ngIf-3')
:marked
Binding to a false expression removes the element subtree from the DOM.
+makeExample('template-syntax/dart/lib/app_component.html', 'NgIf-2')(format=".")
.callout.is-helpful
header Dart difference: No truthy values
:marked :marked
In checked mode, Dart expects Boolean values Template statements cant refer to static properties on the class, nor to
(those with type `bool`) to be either `true` or `false`. top-level variables or functions, such as `window` or `document` from
Even in production mode, the only value Dart treats as `true` is `dart:html`. They cant directly call `print` or functions imported from
the value `true`; all other values are `false`. `dart:math`.
TypeScript and JavaScript, on the other hand, treat
many values (including non-null objects) as true.
A TypeScript Angular 2 program, for example, often has code like
`*ngIf="currentHero"` where a Dart program has code like
`*ngIf="currentHero != null"`.
When converting TypeScript code to Dart code, watch out for block dart-type-exceptions
true/false problems. For example, forgetting the `!= null` .callout.is-helpful
can lead to exceptions in checked mode, such as header Dart difference: Type exceptions
"EXCEPTION: type 'Hero' is not a subtype of type 'bool' of 'boolean expression'". :marked
For more information, see In checked mode, if the template expression result type and the target
[Booleans](https://www.dartlang.org/docs/dart-up-and-running/ch02.html#booleans) property type are not assignment compatible, then a type exception will
in the [Dart language tour](https://www.dartlang.org/docs/dart-up-and-running/ch02.html). be thrown.
+includeShared('{ts}', 'directives-ngIf-4') For information on checked mode, see [Important concepts](https://www.dartlang.org/docs/dart-up-and-running/ch02.html#important-concepts)
+makeExample('template-syntax/dart/lib/app_component.html', 'NgIf-3')(format=".") in the Dart language tour.
+includeShared('{ts}', 'directives-ngIf-5')
+includeShared('{ts}', 'directives-ngSwitch-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'NgSwitch')(format=".")
+includeShared('{ts}', 'directives-ngSwitch-2')
+includeShared('{ts}', 'directives-ngFor-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'NgFor-1')(format=".")
+includeShared('{ts}', 'directives-ngFor-2')
+makeExample('template-syntax/dart/lib/app_component.html', 'NgFor-2')(format=".")
+includeShared('{ts}', 'directives-ngFor-3')
+includeShared('{ts}', 'directives-ngFor-4')
+includeShared('{ts}', 'directives-ngFor-5')
+includeShared('{ts}', 'directives-ngFor-6')
+makeExample('template-syntax/dart/lib/app_component.html', 'NgFor-3')(format=".")
+includeShared('{ts}', 'directives-ngFor-7')
+includeShared('{ts}', 'directives-ngForTrackBy-1')
+makeExample('template-syntax/dart/lib/app_component.dart', 'trackByHeroes')(format=".")
+includeShared('{ts}', 'directives-ngForTrackBy-2')
+makeExample('template-syntax/dart/lib/app_component.html', 'NgForTrackBy-2')(format=".")
+includeShared('{ts}', 'directives-ngForTrackBy-3')
+includeShared('{ts}', 'star-template') block dart-type-exception-example
+includeShared('{ts}', 'star-template-ngIf-1') .callout.is-helpful
+makeExample('template-syntax/dart/lib/app_component.html', 'Template-1')(format=".") header Dart difference: Type exception example
+includeShared('{ts}', 'star-template-ngIf-2a') :marked
+makeExample('template-syntax/dart/lib/app_component.html', 'Template-2a')(format=".") In checked mode, the code above will result in a type exception:
+includeShared('{ts}', 'star-template-ngIf-2') `String` isn't a subtype of `Hero`.
+makeExample('template-syntax/dart/lib/app_component.html', 'Template-2')(format=".")
+includeShared('{ts}', 'star-template-ngIf-3') block dart-class-binding-bug
// Changed from RED to ORANGE, since this isn't so dire a situation in Dart. .callout.is-helpful
.callout.is-important header Angular Issue #6901
header Remember the brackets! :marked
Issue [#6901][6901] prevents us from using `[class]`. As is illustrated
above, in the meantime we can achieve the same effect by binding to
`className`.
[6901]: http://github.com/angular/angular/issues/6901
block style-property-name-dart-diff
.callout.is-helpful
header Dart difference: Style property names
:marked
While [camelCase](glossary.html#camelcase) and
[dash-case](glossary.html#dash-case) style property naming schemes are
equivalent in Angular Dart, only dash-case names are recognized by the
`dart:html` [CssStyleDeclaration][CssSD] methods `getPropertyValue()`
and `setProperty()`. Hence, we recommend only using dash-case for style
property names.
[CssSD]: https://api.dartlang.org/stable/1.16.1/dart-html/CssStyleDeclaration-class.html
block dart-no-truthy-falsey
.callout.is-helpful
header Dart difference: No truthy/falsey values
:marked
In checked mode, Dart expects Boolean values
(those with type `bool`) to be either `true` or `false`.
Even in production mode, the only value Dart treats as `true` is
the value `true`; all other values are `false`.
TypeScript and JavaScript, on the other hand, treat
many values (including non-null objects) as true.
A TypeScript Angular 2 program, for example, often has code like
`*ngIf="currentHero"` where a Dart program has code like
`*ngIf="currentHero != null"`.
When converting TypeScript code to Dart code, watch out for
true/false problems. For example, forgetting the `!= null`
can lead to exceptions in checked mode, such as
"EXCEPTION: type 'Hero' is not a subtype of type 'bool' of 'boolean expression'".
For more information, see
[Booleans](https://www.dartlang.org/docs/dart-up-and-running/ch02.html#booleans)
in the [Dart language tour](https://www.dartlang.org/docs/dart-up-and-running/ch02.html).
block remember-the-brackets
//- Changed from RED to ORANGE, since this isn't so dire a situation in Dart.
.callout.is-important
header Remember the brackets!
:marked
Dont make the mistake of writing `ngIf="currentHero"`!
That syntax assigns the *string* value `"currentHero"` to `ngIf`,
which won't work because `ngIf` expects a `bool`.
block dart-safe-nav-op
.callout.is-helpful
header Dart difference: ?. is a Dart operator
:marked
The safe navigation operator (`?.`) is part of the Dart language.
It's considered a template expression operator because
Angular 2 supports `?.` even in TypeScript and JavaScript apps.
block json-pipe
//- TODO: explain alternative in Dart
//- {{ e | json }} --> {{ e }}
//- which causes the object's toString() method to be invoked.
//- Of course the `json` pipe can be used if the instance supports
//- JSON encoding.
block null-deref-example
:marked :marked
Dont make the mistake of writing `ngIf="currentHero"`! Dart throws an exception, and so does Angular:
That syntax assigns the *string* value "currentHero" to `ngIf`, code-example(format="nocode").
which won't work because `ngIf` expects a bool. EXCEPTION: The null object does not have a getter 'firstName'.
+includeShared('{ts}', 'star-template-ngSwitch-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'NgSwitch-expanded')(format=".")
+includeShared('{ts}', 'star-template-ngSwitch-2')
+includeShared('{ts}', 'star-template-ngFor-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'Template-3a')(format=".")
+includeShared('{ts}', 'star-template-ngFor-2')
+makeExample('template-syntax/dart/lib/app_component.html', 'Template-3')(format=".")
+includeShared('{ts}', 'star-template-ngFor-3')
+makeExample('template-syntax/dart/lib/app_component.html', 'Template-4')(format=".")
+includeShared('{ts}', 'star-template-ngFor-4')
+includeShared('{ts}', 'ref-vars') block safe-op-alt
+makeExample('template-syntax/dart/lib/app_component.html', 'ref-phone')(format=".") //- N/A
+includeShared('{ts}', 'ref-vars-value')
+includeShared('{ts}', 'ref-vars-form-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'ref-form')(format=".")
+includeShared('{ts}', 'ref-vars-form-2')
+makeExample('template-syntax/dart/lib/app_component.html', 'ref-form-a')(format=".")
+includeShared('{ts}', 'ref-vars-form-3')
+includeShared('{ts}', 'inputs-outputs-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'io-1')(format=".")
+includeShared('{ts}', 'inputs-outputs-2')
+makeExample('template-syntax/dart/lib/app_component.html', 'io-2')(format=".")
+includeShared('{ts}', 'inputs-outputs-3')
+makeExample('template-syntax/dart/lib/hero_detail_component.dart', 'input-output-1')(format=".")
:marked
.l-sub-section
:marked
Alternatively, we can identify members in the `inputs` and `outputs` arrays
of the directive metadata, as in this example:
+makeExample('template-syntax/dart/lib/hero_detail_component.dart', 'input-output-2')(format=".")
<br>
:marked
We can specify an input/output property either with a decorator or in a metadata array.
Don't do both!
+includeShared('{ts}', 'inputs-outputs-4')
+includeShared('{ts}', 'inputs-outputs-5')
+makeExample('template-syntax/dart/lib/app_component.html', 'my-click')(format=".")
+includeShared('{ts}', 'inputs-outputs-6')
+makeExample('template-syntax/dart/lib/my_click_directive.dart', 'my-click-output-1')(format=".")
.l-sub-section
:marked
We can also alias property names in the `inputs` and `outputs` arrays.
We write a colon-delimited (`:`) string with
the directive property name on the *left* and the public alias on the *right*:
+makeExample('template-syntax/dart/lib/my_click_directive.dart', 'my-click-output-2')(format=".")
<a id="expression-operators"></a>
.l-main-section
:marked
## Template expression operators
The template expression language employs a subset of Dart syntax supplemented with a few special operators
for specific scenarios. We'll cover two of these operators: _pipe_ and _safe navigation operator_.
.callout.is-helpful
header Dart difference: ?. is a Dart operator
:marked
The safe navigation operator (`?.`) is part of the Dart language.
It's considered a template expression operator because
Angular 2 supports `?.` even in TypeScript and JavaScript apps.
+includeShared('{ts}', 'expression-operators-pipe-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'pipes-1')(format=".")
+includeShared('{ts}', 'expression-operators-pipe-2')
+makeExample('template-syntax/dart/lib/app_component.html', 'pipes-2')(format=".")
+includeShared('{ts}', 'expression-operators-pipe-3')
+makeExample('template-syntax/dart/lib/app_component.html', 'pipes-3')(format=".")
//
NOTE: Intentionally omit discussion of the json pipe.
+includeShared('{ts}', 'expression-operators-pipe-4')
+makeExample('template-syntax/dart/lib/app_component.html', 'pipes-json')(format=".")
+includeShared('{ts}', 'expression-operators-safe-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'safe-2')(format=".")
+includeShared('{ts}', 'expression-operators-safe-2')
+makeExample('template-syntax/dart/lib/app_component.html', 'safe-1')(format=".")
+includeShared('{ts}', 'expression-operators-safe-3')
// +includeShared('{ts}', 'expression-operators-safe-4')
:marked
Dart throws an exception, and so does Angular:
code-example(format="" language="html").
EXCEPTION: The null object does not have a getter 'firstName'.
+includeShared('{ts}', 'expression-operators-safe-5')
+makeExample('template-syntax/dart/lib/app_component.html', 'safe-4')(format=".")
//
NOTE: Intentionally skip ugly null checking you wouldn't do in Dart.
That means skipping the shared sections 'expression-operators-safe-6' & 7,
plus the example 'safe-5'.
:marked
This approach has merit but 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`.
+includeShared('{ts}', 'expression-operators-safe-8')
+makeExample('template-syntax/dart/lib/app_component.html', 'safe-6')(format=".")
+includeShared('{ts}', 'expression-operators-safe-9')
+includeShared('{ts}', 'summary')

File diff suppressed because it is too large Load Diff

View File

@ -67,6 +67,11 @@ $hero-padding: ($unit * 10) ($unit * 6) ($unit * 7);
} }
.badges { .badges {
display: flex;
justify-content: flex-start;
align-content: space-around;
align-items: center;
margin-top: 4px; margin-top: 4px;
.status-badge { .status-badge {