docs(template-syntax): publish Dart version, tweak TypeScript version
closes #875
This commit is contained in:
parent
3bedd33814
commit
e725136d98
|
@ -33,11 +33,7 @@ class AppComponent implements OnInit, AfterViewInit {
|
|||
String heroName;
|
||||
String help;
|
||||
String actionName = 'Go for it';
|
||||
// String badCurly = 'special'; // XXX: This isn't working.
|
||||
// String badCurly = 'bad, curly'; // XXX: This isn't working.
|
||||
// String badCurly = 'bad curly'; // XXX: This isn't working.
|
||||
String badCurly = 'bad'; // XXX: This isn't working.
|
||||
// List<String> badCurly = ['bad', 'curly']; // XXX: This isn't working.
|
||||
String badCurly = 'bad curly';
|
||||
String classes = 'special';
|
||||
bool canSave = true;
|
||||
bool isActive = false;
|
||||
|
|
|
@ -184,17 +184,15 @@ button</button>
|
|||
<!-- #enddocregion property-binding-5 -->
|
||||
|
||||
<!-- #docregion property-binding-6 -->
|
||||
<!--
|
||||
BAD!
|
||||
HeroDetailComponent.hero expects a Hero object,
|
||||
not the string "currentHero"
|
||||
<!-- BAD! HeroDetailComponent.hero expects a Hero object,
|
||||
not the string "currentHero".
|
||||
|
||||
<hero-detail hero="currentHero"></hero-detail>
|
||||
|
||||
In checked mode, uncommenting the hero-detail above causes this:
|
||||
EXCEPTION: type 'String' is not a subtype of type 'Hero' of 'value'. -->
|
||||
<hero-detail hero="currentHero"></hero-detail> -->
|
||||
<!-- #enddocregion property-binding-6 -->
|
||||
|
||||
<!-- In checked mode, uncommenting the hero-detail above causes this:
|
||||
EXCEPTION: type 'String' is not a subtype of type 'Hero' of 'value'. -->
|
||||
|
||||
<!-- #docregion property-binding-7 -->
|
||||
<hero-detail prefix="You are my" [hero]="currentHero"></hero-detail>
|
||||
<!-- #enddocregion property-binding-7 -->
|
||||
|
@ -260,8 +258,8 @@ Property bound: <img [src]="heroImageUrl">
|
|||
<!-- #docregion class-binding-2 -->
|
||||
<!-- reset/override all class names with a binding -->
|
||||
<div class="bad curly special"
|
||||
[class]="badCurly">Bad curly</div> <!-- Doesn't work, due to
|
||||
github.com/angular/angular/issues/6901 -->
|
||||
[class]="badCurly">Bad curly</div>
|
||||
<!-- Doesn't work, due to github.com/angular/angular/issues/6901 -->
|
||||
<!-- #enddocregion class-binding-2 -->
|
||||
|
||||
<!-- #docregion class-binding-3 -->
|
||||
|
@ -493,16 +491,16 @@ bindon-ngModel
|
|||
You picked ...
|
||||
<!-- #docregion NgSwitch, NgSwitch-expanded -->
|
||||
<span [ngSwitch]="toeChoice">
|
||||
<!-- #enddocregion NgSwitch -->
|
||||
<!-- #enddocregion NgSwitch -->
|
||||
|
||||
<!-- with *NgSwitch -->
|
||||
<!-- #docregion NgSwitch -->
|
||||
<!-- #docregion NgSwitch -->
|
||||
<span *ngSwitchWhen="'Eenie'">Eenie</span>
|
||||
<span *ngSwitchWhen="'Meanie'">Meanie</span>
|
||||
<span *ngSwitchWhen="'Miney'">Miney</span>
|
||||
<span *ngSwitchWhen="'Moe'">Moe</span>
|
||||
<span *ngSwitchDefault>other</span>
|
||||
<!-- #enddocregion NgSwitch -->
|
||||
<!-- #enddocregion NgSwitch -->
|
||||
|
||||
<!-- with <template> -->
|
||||
<template ngSwitchWhen="Eenie"><span>Eenie</span></template>
|
||||
|
@ -511,7 +509,7 @@ bindon-ngModel
|
|||
<template ngSwitchWhen="Moe"><span>Moe</span></template>
|
||||
<template ngSwitchDefault><span>other</span></template>
|
||||
|
||||
<!-- #docregion NgSwitch -->
|
||||
<!-- #docregion NgSwitch -->
|
||||
</span>
|
||||
<!-- #enddocregion NgSwitch, NgSwitch-expanded -->
|
||||
</div>
|
||||
|
|
|
@ -1,412 +0,0 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
+includeShared('{ts}', 'intro')
|
||||
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'html-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'my-first-app')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'html-2')
|
||||
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'interpolation-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'first-interpolation')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'interpolation-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'title+image')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'interpolation-3')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'sum-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'interpolation-4')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'sum-2')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'interpolation-5')
|
||||
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', '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: **[QUESTION: is this list correct? I removed mentions of chaining with , and ;.]**
|
||||
|
||||
* assignments (`=`, `+=`, `-=`, ...)
|
||||
* creating instances using `new` or `const`
|
||||
* increment and decrement (`++` and `--`)
|
||||
|
||||
Other notable differences from Dart syntax include:
|
||||
**[QUESTION: I wasn't able to use Dart interpolation inside a String,
|
||||
which I had just assumed would work. How should we talk about that?
|
||||
What else isn't allowed?]**
|
||||
|
||||
* no support for the bitwise operators `|` and `&`
|
||||
* new [template expression operators](#expression-operators), such as `|`
|
||||
.callout.is-helpful
|
||||
header Dart difference: Template expression operators
|
||||
:marked
|
||||
[PENDING: say something about stuff you might find in a24ts template expressions
|
||||
but not in dart template expressions, and vice versa.]
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'template-expressions-context')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', '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/latest/guide/template-syntax.jade', '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 (`;`) and commas (`,`).
|
||||
**[QUESTION: is that true — would `,` really work? is "chaining" really the word we want to use?]**
|
||||
|
||||
However, certain Dart syntax is not allowed:
|
||||
* the `new` and `const` keywords **[QUESTION: I guessed about `const`. Is it true?]**
|
||||
* increment and decrement operators, `++` and `--`
|
||||
* operator assignment, such as `+=` and `-=`
|
||||
* the bitwise operators `|` and `&`
|
||||
* the [template expression operators](#expression-operators)
|
||||
**[QUESTION: can you really not use `?.`?]**
|
||||
|
||||
.callout.is-helpful
|
||||
header Dart difference: Template statement operators
|
||||
:marked
|
||||
[PENDING: say something about stuff you might find in a24ts statements
|
||||
but not in dart statements, and vice versa.]
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'template-statements-3')
|
||||
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'binding-syntax-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'img+button')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'binding-syntax-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'hero-detail-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'binding-syntax-3')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'disabled-button-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'binding-syntax-4')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'binding-syntax-attribute-vs-property')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'binding-syntax-5')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'binding-syntax-world-without-attributes')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'binding-syntax-targets')
|
||||
|
||||
<div width="90%">
|
||||
table
|
||||
tr
|
||||
th Binding type
|
||||
th Target
|
||||
th Examples
|
||||
tr
|
||||
td Property
|
||||
td.
|
||||
Element property<br>
|
||||
Component property<br>
|
||||
Directive property
|
||||
td
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-syntax-1')(format=".")
|
||||
tr
|
||||
td Event
|
||||
td.
|
||||
Element event<br>
|
||||
Component event<br>
|
||||
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.
|
||||
<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/latest/guide/template-syntax.jade', 'binding-syntax-end')
|
||||
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'property-binding-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'property-binding-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-2')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'property-binding-3')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-3')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'property-binding-4')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-4')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'property-binding-5')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'property-binding-6')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'property-binding-7')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'property-binding-8')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-5')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'property-binding-9')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-3')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'property-binding-10')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-4')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'property-binding-11')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-6')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'property-binding-12')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-7')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'property-binding-13')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-vs-interpolation')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'property-binding-14')
|
||||
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'other-bindings-1')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'other-bindings-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'attrib-binding-colspan')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'other-bindings-3')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'attrib-binding-aria')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'other-bindings-class-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'class-binding-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'other-bindings-class-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'class-binding-2')(format=".")
|
||||
//
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', '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/latest/guide/template-syntax.jade', 'other-bindings-class-4')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'other-bindings-style-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'style-binding-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'other-bindings-style-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'style-binding-2')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'other-bindings-style-3')
|
||||
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'event-binding-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'event-binding-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'event-binding-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'event-binding-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'event-binding-3')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'event-binding-2')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'event-binding-4')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'event-binding-3')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'event-binding-5')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'without-NgModel')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', '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/latest/guide/template-syntax.jade', 'event-binding-7')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'event-binding-to-component')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'event-binding-8')
|
||||
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'ngModel-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'NgModel-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'ngModel-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'NgModel-2')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'ngModel-3')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'without-NgModel')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'ngModel-4')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'NgModel-3')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'ngModel-5')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'NgModel-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'ngModel-6')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'NgModel-4')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'ngModel-7')
|
||||
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'event-binding-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-2')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-ngClass-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'class-binding-3a')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', '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/latest/guide/template-syntax.jade', 'directives-ngClass-3')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'NgClass-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-ngStyle-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'NgStyle-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-ngStyle-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.dart', 'setStyles')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-ngStyle-3')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'NgStyle-2')(format=".")
|
||||
//
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', '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/latest/guide/template-syntax.jade', 'directives-ngIf-2')
|
||||
//
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', '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 error messages such as
|
||||
"[TODO: Put error message here]".
|
||||
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/latest/guide/template-syntax.jade', 'directives-ngIf-4')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'NgIf-3')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-ngIf-5')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-ngSwitch-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'NgSwitch')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-ngSwitch-2')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-ngFor-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'NgFor-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-ngFor-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'NgFor-2')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-ngFor-3')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-ngFor-4')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-ngFor-5')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-ngFor-6')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'NgFor-3')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-ngFor-7')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-ngForTrackBy-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.dart', 'trackByHeroes')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-ngForTrackBy-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'NgForTrackBy-2')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'directives-ngForTrackBy-3')
|
||||
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'star-template')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'star-template-ngIf-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'Template-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'star-template-ngIf-2a')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'Template-2a')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'star-template-ngIf-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'Template-2')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', '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. **[QUESTION: Did I get that right?]**
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'star-template-ngSwitch-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'NgSwitch-expanded')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'star-template-ngSwitch-2')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'star-template-ngFor-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'Template-3a')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'star-template-ngFor-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'Template-3')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'star-template-ngFor-3')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'Template-4')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'star-template-ngFor-4')
|
||||
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'local-vars-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'Template-4')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'local-vars-2')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'local-vars-refs')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'var-phone')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'local-vars-value')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'local-vars-form-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'var-form')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'local-vars-form-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'var-form-a')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'local-vars-form-3')
|
||||
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'inputs-outputs-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'io-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'inputs-outputs-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'io-2')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', '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/latest/guide/template-syntax.jade', 'inputs-outputs-4')
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'inputs-outputs-5')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'my-click')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', '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 _Elvis_.
|
||||
.callout.is-helpful
|
||||
header Dart difference: ?. is a Dart operator
|
||||
:marked
|
||||
The Elvis 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/latest/guide/template-syntax.jade', 'expression-operators-pipe-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'pipes-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'expression-operators-pipe-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'pipes-2')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', '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/latest/guide/template-syntax.jade', 'expression-operators-pipe-4')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'pipes-json')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'expression-operators-elvis-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'elvis-2')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'expression-operators-elvis-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'elvis-1')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'expression-operators-elvis-3')
|
||||
// +includeShared('../../../ts/latest/guide/template-syntax.jade', 'expression-operators-elvis-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/latest/guide/template-syntax.jade', 'expression-operators-elvis-5')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'elvis-4')(format=".")
|
||||
|
||||
//
|
||||
NOTE: Intentionally skip ugly null checking you wouldn't do in Dart.
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'expression-operators-elvis-6')
|
||||
+make---dashed-so-does-not-show-as-fragment-error---Example('template-syntax/dart/lib/app_component.html', 'elvis-5')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'expression-operators-elvis-7')
|
||||
: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/latest/guide/template-syntax.jade', 'expression-operators-elvis-8')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'elvis-6')(format=".")
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'expression-operators-elvis-9')
|
||||
|
||||
+includeShared('../../../ts/latest/guide/template-syntax.jade', 'summary')
|
|
@ -1,12 +1,410 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
+includeShared('{ts}', 'intro')
|
||||
|
||||
:marked
|
||||
We're working on the Dart version of this chapter.
|
||||
In the meantime, please see these resources:
|
||||
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).
|
||||
|
||||
* [Template Syntax](/docs/ts/latest/guide/template-syntax.html):
|
||||
The TypeScript version of this chapter
|
||||
+includeShared('{ts}', 'html-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'my-first-app')(format=".")
|
||||
+includeShared('{ts}', 'html-2')
|
||||
|
||||
* [Dart source code](https://github.com/angular/angular.io/tree/master/public/docs/_examples/template-syntax/dart):
|
||||
A preliminary version of the example code that will appear in this chapter
|
||||
+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')
|
||||
|
||||
<div width="90%">
|
||||
table
|
||||
tr
|
||||
th Binding type
|
||||
th Target
|
||||
th Examples
|
||||
tr
|
||||
td Property
|
||||
td.
|
||||
Element property<br>
|
||||
Component property<br>
|
||||
Directive property
|
||||
td
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'property-binding-syntax-1')(format=".")
|
||||
tr
|
||||
td Event
|
||||
td.
|
||||
Element event<br>
|
||||
Component event<br>
|
||||
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.
|
||||
<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
|
||||
In checked mode, uncommenting the `<hero-detail>` 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')
|
||||
<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
|
||||
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}', 'local-vars-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'Template-4')(format=".")
|
||||
+includeShared('{ts}', 'local-vars-2')
|
||||
+includeShared('{ts}', 'local-vars-refs')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'var-phone')(format=".")
|
||||
+includeShared('{ts}', 'local-vars-value')
|
||||
+includeShared('{ts}', 'local-vars-form-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'var-form')(format=".")
|
||||
+includeShared('{ts}', 'local-vars-form-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'var-form-a')(format=".")
|
||||
+includeShared('{ts}', 'local-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 _Elvis_.
|
||||
.callout.is-helpful
|
||||
header Dart difference: ?. is a Dart operator
|
||||
:marked
|
||||
The Elvis 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-elvis-1')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'elvis-2')(format=".")
|
||||
+includeShared('{ts}', 'expression-operators-elvis-2')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'elvis-1')(format=".")
|
||||
+includeShared('{ts}', 'expression-operators-elvis-3')
|
||||
// +includeShared('{ts}', 'expression-operators-elvis-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-elvis-5')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'elvis-4')(format=".")
|
||||
|
||||
//
|
||||
NOTE: Intentionally skip ugly null checking you wouldn't do in Dart.
|
||||
That means skipping the shared sections 'expression-operators-elvis-6' & 7,
|
||||
plus the example 'elvis-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-elvis-8')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'elvis-6')(format=".")
|
||||
+includeShared('{ts}', 'expression-operators-elvis-9')
|
||||
|
||||
+includeShared('{ts}', 'summary')
|
||||
|
|
|
@ -574,20 +574,20 @@ table
|
|||
|
||||
The expression could call something like `getFoo()`. Only we know what `getFoo()` does.
|
||||
If `getFoo()` changes something and we happen to be binding to that something, we risk an unpleasant experience. Angular may or may not display the changed value. Angular may detect the change and throw a warning error. Our general advice: stick to data properties and to methods that return values and do no more.
|
||||
|
||||
|
||||
### Return the proper type
|
||||
The template expression should evaluate to the type of value expected by the target property.
|
||||
Return a string if the target property expects a string.
|
||||
The template expression should evaluate to the type of value expected by the target property.
|
||||
Return a string if the target property expects a string.
|
||||
Return a number if the target property expects a number.
|
||||
Return an object if the target property expects an object.
|
||||
|
||||
The `hero` property of the `HeroDetail` component expects a `Hero` object, which is exactly what we’re sending in the property binding:
|
||||
The `hero` property of the `HeroDetail` component expects a `Hero` object, which is exactly what we’re sending in the property binding:
|
||||
// #enddocregion property-binding-10
|
||||
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-4')(format=".")
|
||||
// #docregion property-binding-11
|
||||
:marked
|
||||
### Remember the brackets
|
||||
The brackets tell Angular to evaluate the template expression.
|
||||
The brackets tell Angular to evaluate the template expression.
|
||||
If we forget the brackets, Angular treats the string as a constant and *initializes the target property* with that string.
|
||||
It does *not* evaluate the string!
|
||||
|
||||
|
@ -598,15 +598,15 @@ table
|
|||
a(id="one-time-initialization")
|
||||
:marked
|
||||
### One-time string initialization
|
||||
We *should omit the brackets* when
|
||||
* the target property accepts a string value
|
||||
* the string is a fixed value that we can bake into the template
|
||||
* this initial value never changes
|
||||
|
||||
We routinely initialize attributes this way in standard HTML and it works
|
||||
We *should* omit the brackets when all of the following are true:
|
||||
* The target property accepts a string value.
|
||||
* The string is a fixed value that we can bake into the template.
|
||||
* This initial value never changes.
|
||||
|
||||
We routinely initialize attributes this way in standard HTML, and it works
|
||||
just as well for directive and component property initialization.
|
||||
In the following example, we initialize the `prefix` property of the `HeroDetailComponent` to a fixed string,
|
||||
not a template expression. Angular sets it and forgets it.
|
||||
The following example initializes the `prefix` property of the `HeroDetailComponent` to a fixed string,
|
||||
not a template expression. Angular sets it and forgets it.
|
||||
// #enddocregion property-binding-12
|
||||
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-7')(format=".")
|
||||
// #docregion property-binding-13
|
||||
|
@ -832,9 +832,9 @@ code-example(format="", language="html").
|
|||
Parent directives listen for the event by binding to this property and accessing the payload through the `$event` object.
|
||||
|
||||
Consider a `HeroDetailComponent` that presents hero information and responds to user actions.
|
||||
Although the `HeroDetailComponent` has a delete button it doesn't know how to delete the hero itself.
|
||||
The best it can do is raise an event reporting the user's delete request.
|
||||
|
||||
Although the `HeroDetailComponent` has a delete button it doesn't know how to delete the hero itself.
|
||||
The best it can do is raise an event reporting the user's delete request.
|
||||
|
||||
Here are the pertinent excerpts from that `HeroDetailComponent`:
|
||||
// #enddocregion event-binding-6
|
||||
+makeExample('template-syntax/ts/app/hero-detail.component.ts',
|
||||
|
@ -845,9 +845,9 @@ code-example(format="", language="html").
|
|||
// #docregion event-binding-7
|
||||
:marked
|
||||
The component defines a `deleteRequest` property that returns an `EventEmitter`.
|
||||
When the user clicks *delete*, the component invokes the `delete()` method
|
||||
When the user clicks *delete*, the component invokes the `delete()` method
|
||||
which tells the `EventEmitter` to emit a `Hero` object.
|
||||
|
||||
|
||||
Now imagine a hosting parent component that binds to the `HeroDetailComponent`'s `deleteRequest` event.
|
||||
// #enddocregion event-binding-7
|
||||
|
||||
|
@ -1112,17 +1112,17 @@ figure.image-display
|
|||
We bind the parent `NgSwitch` directive to an expression returning a *switch value*.
|
||||
The value is a string in this example, but it can be a value of any type.
|
||||
|
||||
In this example, the parent `NgSwitch` directive controls a set of child `<span>` elements.
|
||||
In this example, the parent `NgSwitch` directive controls a set of child `<span>` elements.
|
||||
A `<span>` is either pegged to a *match value* expression or marked as the default.
|
||||
|
||||
**At any particular moment, at most one of these *spans* is in the DOM.**
|
||||
|
||||
If the *span*’s *match value* equals the switch value, Angular adds the `<span>` to the DOM.
|
||||
If none of the *spans* is a match, Angular adds the default *span* to the DOM.
|
||||
If the *span*’s *match value* equals the switch value, Angular adds the `<span>` to the DOM.
|
||||
If none of the *spans* is a match, Angular adds the default *span* to the DOM.
|
||||
Angular removes and destroys all other *spans*.
|
||||
.l-sub-section
|
||||
:marked
|
||||
We could substitute any element for the *span* in this example.
|
||||
We could substitute any element for the *span* in this example.
|
||||
That element could be a `<div>` with a vast subtree of its own elements.
|
||||
Only the matching `<div>` and its subtree would appear in the DOM;
|
||||
the others would be removed.
|
||||
|
@ -1131,11 +1131,11 @@ figure.image-display
|
|||
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 element
|
||||
|
||||
|
||||
.alert.is-critical
|
||||
:marked
|
||||
**Do *not*** put the asterisk (`*`) in front of `ngSwitch`. Use the property binding instead.
|
||||
|
||||
|
||||
**Do** put the asterisk (`*`) in front of `ngSwitchWhen` and `ngSwitchDefault`.
|
||||
For more information, see [\* and <template>](#star-template).
|
||||
// #enddocregion directives-ngSwitch-2
|
||||
|
@ -1215,34 +1215,34 @@ figure.image-display
|
|||
#### NgForTrackBy
|
||||
The `ngFor` directive has the potential to perform poorly, especially with large lists.
|
||||
A small change to one item, an item removed, or an item added can trigger a cascade of DOM manipulations.
|
||||
|
||||
For example, we could refresh the list of heroes by re-querying the server.
|
||||
|
||||
For example, we could refresh the list of heroes by re-querying the server.
|
||||
The refreshed list probably contains most, if not all, of the previously displayed heroes.
|
||||
|
||||
|
||||
*We* know this because the `id` of each hero hasn't changed.
|
||||
But Angular sees only a fresh list of new object references.
|
||||
But Angular sees only a fresh list of new object references.
|
||||
It has no choice but to tear down the old list, discard those DOM elements, and re-build a new list with new DOM elements.
|
||||
|
||||
|
||||
Angular can avoid this churn if we give it a *tracking* function that tells it what we know:
|
||||
that two objects with the same `hero.id` are the same *hero*. Here is such a function:
|
||||
// #enddocregion directives-ngForTrackBy-1
|
||||
+makeExample('template-syntax/ts/app/app.component.ts', 'trackByHeroes')(format=".")
|
||||
// #docregion directives-ngForTrackBy-2
|
||||
:marked
|
||||
Now set the `NgForTrackBy` directive to that *tracking* function.
|
||||
Now set the `NgForTrackBy` directive to that *tracking* function.
|
||||
Angular offers a variety of equivalent syntax choices including these two:
|
||||
// #enddocregion directives-ngForTrackBy-2
|
||||
+makeExample('template-syntax/ts/app/app.component.html', 'NgForTrackBy-2')(format=".")
|
||||
// #docregion directives-ngForTrackBy-3
|
||||
:marked
|
||||
The *tracking* function doesn't eliminate all DOM changes.
|
||||
Angular may have to update the DOM element if the same-hero *properties* have changed.
|
||||
Angular may have to update the DOM element if the same-hero *properties* have changed.
|
||||
But if the properties haven't changed — and most of the time they will not have changed —
|
||||
Angular can leave those DOM elements alone. The list UI will be smoother and more responsive.
|
||||
|
||||
|
||||
Here is an illustration of the `NgForTrackBy` effect.
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/template-syntax/ng-for-track-by-anim.gif' alt="NgForTrackBy")
|
||||
img(src='/resources/images/devguide/template-syntax/ng-for-track-by-anim.gif' alt="NgForTrackBy")
|
||||
// #enddocregion directives-ngForTrackBy-3
|
||||
|
||||
// #docregion star-template
|
||||
|
@ -1256,11 +1256,11 @@ figure.image-display
|
|||
The `*` 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.
|
||||
|
||||
|
||||
We didn't see the `<template>` tags because the `*` prefix syntax allowed us to skip those tags and
|
||||
focus directly on the HTML element that we are including, excluding, or repeating.
|
||||
|
||||
In this section we go under the hood and see how
|
||||
|
||||
In this section we go under the hood and see how
|
||||
Angular strips away the `*` and expands the HTML into the `<template>` tags for us.
|
||||
// #enddocregion star-template
|
||||
|
||||
|
@ -1272,11 +1272,11 @@ figure.image-display
|
|||
+makeExample('template-syntax/ts/app/app.component.html', 'Template-1')(format=".")
|
||||
// #docregion star-template-ngIf-2a
|
||||
:marked
|
||||
The `currentHero` is referenced twice, first as the true/false condition for `NgIf` and
|
||||
The `currentHero` is referenced twice, first as the true/false condition for `NgIf` and
|
||||
again as the actual hero passed into the `HeroDetailComponent`.
|
||||
|
||||
The first expansion step transports the `ngIf` (without the `*` prefix) and its contents
|
||||
into an expression assigned to a `template` directive.
|
||||
|
||||
The first expansion step transports the `ngIf` (without the `*` prefix) and its contents
|
||||
into an expression assigned to a `template` directive.
|
||||
// #enddocregion star-template-ngIf-2a
|
||||
+makeExample('template-syntax/ts/app/app.component.html', 'Template-2a')(format=".")
|
||||
// #docregion star-template-ngIf-2
|
||||
|
@ -1304,18 +1304,18 @@ figure.image-display
|
|||
// #docregion star-template-ngSwitch-1
|
||||
:marked
|
||||
### Expanding `*ngSwitch`
|
||||
A similar transformation applies to `*ngSwitch`. We can de-sugar the syntax ourselves.
|
||||
A similar transformation applies to `*ngSwitch`. We can de-sugar the syntax ourselves.
|
||||
Here's an example, first with `*ngSwitchWhen` and `*ngSwitchDefault` and then again with `<template>` tags:
|
||||
// #enddocregion star-template-ngSwitch-1
|
||||
+makeExample('template-syntax/ts/app/app.component.html', 'NgSwitch-expanded')
|
||||
// #enddocregion star-template-ngSwitch-1
|
||||
+makeExample('template-syntax/ts/app/app.component.html', 'NgSwitch-expanded')(format=".")
|
||||
// #docregion star-template-ngSwitch-2
|
||||
:marked
|
||||
The `*ngSwitchWhen` and `*ngSwitchDefault` expand in exactly the same manner as `*ngIf`,
|
||||
wrapping their former elements in `<template>` tags.
|
||||
|
||||
Now we can see why the `ngSwitch` itself is not prefixed with an asterisk (*).
|
||||
|
||||
Now we can see why the `ngSwitch` itself is not prefixed with an asterisk (*).
|
||||
It does not define content. It's job is to control a collection of templates.
|
||||
|
||||
|
||||
In this case, it governs two sets of `NgSwitchWhen` and `NgSwitchDefault` directives.
|
||||
We should expect it to display the values of the selected template twice,
|
||||
once for the (*) prefixed version and once for the expanded template version.
|
||||
|
|
Loading…
Reference in New Issue