include ../_util-fns +includeShared('{ts}', 'intro') :marked 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 Arrays in JavaScript correspond to lists in Dart (instances of the `List` class). This chapter uses _array_ and _list_ interchangeably. For more information, see [Lists](https://www.dartlang.org/docs/dart-up-and-running/ch02.html#lists) in the [Dart language tour](https://www.dartlang.org/docs/dart-up-and-running/ch02.html). +includeShared('{ts}', 'template-statements-1') :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')
table tr th Binding type th Target th Examples tr td Property td. Element property
Component property
Directive property td +makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-syntax-1')(format=".") tr td Event td. Element event
Component event
Directive 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 exception) td +makeExample('template-syntax/dart/lib/app_component.html', 'attribute-binding-syntax-1')(format=".") tr td Class td. class property td +makeExample('template-syntax/dart/lib/app_component.html', 'class-binding-syntax-1')(format=".") tr td Style td. style property td +makeExample('template-syntax/dart/lib/app_component.html', 'style-binding-syntax-1')(format=".")
+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 In checked mode, uncommenting the `` element above causes a type exception, because `String` isn't a subtype of `Hero`. For information on checked mode, see [Important concepts](https://www.dartlang.org/docs/dart-up-and-running/ch02.html#important-concepts) in the Dart language tour. +includeShared('{ts}', 'property-binding-12') +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') +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') .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 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). +includeShared('{ts}', 'directives-ngIf-4') +makeExample('template-syntax/dart/lib/app_component.html', 'NgIf-3')(format=".") +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') +includeShared('{ts}', 'star-template-ngIf-1') +makeExample('template-syntax/dart/lib/app_component.html', 'Template-1')(format=".") +includeShared('{ts}', 'star-template-ngIf-2a') +makeExample('template-syntax/dart/lib/app_component.html', 'Template-2a')(format=".") +includeShared('{ts}', 'star-template-ngIf-2') +makeExample('template-syntax/dart/lib/app_component.html', 'Template-2')(format=".") +includeShared('{ts}', 'star-template-ngIf-3') // Changed from RED to ORANGE, since this isn't so dire a situation in Dart. .callout.is-important header Remember the brackets! :marked Don’t 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. +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') +makeExample('template-syntax/dart/lib/app_component.html', 'ref-phone')(format=".") +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=".")
: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=".") .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')