parent
0e63b1f39b
commit
4097c67b59
|
@ -34,7 +34,7 @@
|
|||
<a href="#local-vars">Template local variables</a><br>
|
||||
<a href="#inputs-and-outputs">Inputs and outputs</a><br>
|
||||
<a href="#pipes">Pipes</a><br>
|
||||
<a href="#elvis">Elvis <i>?.</i></a><br>
|
||||
<a href="#safe-navigation-operator">Safe navigation operator <i>?.</i></a><br>
|
||||
<!--<a href="#enums">Enums</a><br>-->
|
||||
|
||||
<!-- Interpolation and expressions -->
|
||||
|
@ -738,25 +738,25 @@ bindon-ngModel
|
|||
|
||||
<a class="to-toc" href="#toc">top</a>
|
||||
|
||||
<!-- Null values and the Elvis operator -->
|
||||
<hr><h2 id="elvis">Elvis <i>?.</i></h2>
|
||||
<!-- Null values and the safe navigation operator -->
|
||||
<hr><h2 id="safe-navigation-operator">Safe navigation operator <i>?.</i></h2>
|
||||
|
||||
<div>
|
||||
<!-- #docregion elvis-1 -->
|
||||
<!-- #docregion safe-1 -->
|
||||
The title is {{ title }}
|
||||
<!-- #enddocregion elvis-1 -->
|
||||
<!-- #enddocregion safe-1 -->
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<!-- #docregion elvis-2 -->
|
||||
<!-- #docregion safe-2 -->
|
||||
The current hero's name is {{currentHero?.firstName}}
|
||||
<!-- #enddocregion elvis-2 -->
|
||||
<!-- #enddocregion safe-2 -->
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<!-- #docregion elvis-3 -->
|
||||
<!-- #docregion safe-3 -->
|
||||
The current hero's name is {{currentHero.firstName}}
|
||||
<!-- #enddocregion elvis-3 -->
|
||||
<!-- #enddocregion safe-3 -->
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -768,18 +768,18 @@ The null hero's name is {{nullHero.firstName}}
|
|||
EXCEPTION: The null object does not have a getter 'firstName'.
|
||||
-->
|
||||
|
||||
<!-- #docregion elvis-4 -->
|
||||
<!-- #docregion safe-4 -->
|
||||
<!--No hero, div not displayed, no error -->
|
||||
<div *ngIf="nullHero != null">The null hero's name is {{nullHero.firstName}}</div>
|
||||
<!-- #enddocregion elvis-4 -->
|
||||
<!-- #enddocregion safe-4 -->
|
||||
|
||||
<!-- skip docregion elvis-5 -->
|
||||
<!-- skip docregion safe-5 -->
|
||||
|
||||
<div>
|
||||
<!-- #docregion elvis-6 -->
|
||||
<!-- #docregion safe-6 -->
|
||||
<!-- No hero, no problem! -->
|
||||
The null hero's name is {{nullHero?.firstName}}
|
||||
<!-- #enddocregion elvis-6 -->
|
||||
<!-- #enddocregion safe-6 -->
|
||||
</div>
|
||||
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
<a href="#local-vars">Template local variables</a><br>
|
||||
<a href="#inputs-and-outputs">Inputs and outputs</a><br>
|
||||
<a href="#pipes">Pipes</a><br>
|
||||
<a href="#elvis">Elvis <i>?.</i></a><br>
|
||||
<a href="#safe-navigation-operator">Safe navigation operator <i>?.</i></a><br>
|
||||
<a href="#enums">Enums</a><br>
|
||||
|
||||
<!-- Interpolation and expressions -->
|
||||
|
@ -739,25 +739,25 @@ After setClasses(), the classes are "{{classDiv.className}}"
|
|||
|
||||
<a class="to-toc" href="#toc">top</a>
|
||||
|
||||
<!-- Null values and the Elvis operator -->
|
||||
<hr><h2 id="elvis">Elvis <i>?.</i></h2>
|
||||
<!-- Null values and the safe navigation operator -->
|
||||
<hr><h2 id="safe-navigation-operator">Safe navigation operator <i>?.</i></h2>
|
||||
|
||||
<div>
|
||||
<!-- #docregion elvis-1 -->
|
||||
<!-- #docregion safe-1 -->
|
||||
The title is {{ title }}
|
||||
<!-- #enddocregion elvis-1 -->
|
||||
<!-- #enddocregion safe-1 -->
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<!-- #docregion elvis-2 -->
|
||||
<!-- #docregion safe-2 -->
|
||||
The current hero's name is {{currentHero?.firstName}}
|
||||
<!-- #enddocregion elvis-2 -->
|
||||
<!-- #enddocregion safe-2 -->
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<!-- #docregion elvis-3 -->
|
||||
<!-- #docregion safe-3 -->
|
||||
The current hero's name is {{currentHero.firstName}}
|
||||
<!-- #enddocregion elvis-3 -->
|
||||
<!-- #enddocregion safe-3 -->
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -768,22 +768,22 @@ See console log
|
|||
TypeError: Cannot read property 'firstName' of null in [null]
|
||||
-->
|
||||
|
||||
<!-- #docregion elvis-4 -->
|
||||
<!-- #docregion safe-4 -->
|
||||
<!--No hero, div not displayed, no error -->
|
||||
<div *ngIf="nullHero">The null hero's name is {{nullHero.firstName}}</div>
|
||||
<!-- #enddocregion elvis-4 -->
|
||||
<!-- #enddocregion safe-4 -->
|
||||
|
||||
<div>
|
||||
<!-- #docregion elvis-5 -->
|
||||
<!-- #docregion safe-5 -->
|
||||
The null hero's name is {{nullHero && nullHero.firstName}}
|
||||
<!-- #enddocregion elvis-5 -->
|
||||
<!-- #enddocregion safe-5 -->
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<!-- #docregion elvis-6 -->
|
||||
<!-- #docregion safe-6 -->
|
||||
<!-- No hero, no problem! -->
|
||||
The null hero's name is {{nullHero?.firstName}}
|
||||
<!-- #enddocregion elvis-6 -->
|
||||
<!-- #enddocregion safe-6 -->
|
||||
</div>
|
||||
|
||||
|
||||
|
|
|
@ -366,11 +366,11 @@ table
|
|||
: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_.
|
||||
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 Elvis operator (`?.`) is part of the Dart language.
|
||||
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')
|
||||
|
@ -383,28 +383,28 @@ table
|
|||
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')
|
||||
+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-elvis-5')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'elvis-4')(format=".")
|
||||
+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-elvis-6' & 7,
|
||||
plus the example 'elvis-5'.
|
||||
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-elvis-8')
|
||||
+makeExample('template-syntax/dart/lib/app_component.html', 'elvis-6')(format=".")
|
||||
+includeShared('{ts}', 'expression-operators-elvis-9')
|
||||
+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')
|
||||
|
|
|
@ -28,7 +28,7 @@ include ../_util-fns
|
|||
* [Input and output properties](#inputs-outputs)
|
||||
* [Template expression operators](#expression-operators)
|
||||
* [pipe](#pipe)
|
||||
* ["elvis" (?.)](#elvis)
|
||||
* ["safe navigation operator" (?.)](#safe-navigation-operator)
|
||||
// #enddocregion intro
|
||||
.l-sub-section
|
||||
:marked
|
||||
|
@ -1576,7 +1576,7 @@ figure.image-display
|
|||
:marked
|
||||
## Template expression operators
|
||||
The template expression language employs a subset of JavaScript syntax supplemented with a few special operators
|
||||
for specific scenarios. We'll cover two of these operators: _pipe_ and _Elvis_.
|
||||
for specific scenarios. We'll cover two of these operators: _pipe_ and _safe navigation operator_.
|
||||
// #enddocregion expression-operators
|
||||
|
||||
// #docregion expression-operators-pipe-1
|
||||
|
@ -1608,23 +1608,23 @@ figure.image-display
|
|||
// #enddocregion expression-operators-pipe-4
|
||||
+makeExample('template-syntax/ts/app/app.component.html', 'pipes-json')(format=".")
|
||||
|
||||
// #docregion expression-operators-elvis-1
|
||||
// #docregion expression-operators-safe-1
|
||||
:marked
|
||||
<a id="elvis"></a>
|
||||
### The Elvis operator ( ?. ) and null property paths
|
||||
<a id="safe-navigation-operator"></a>
|
||||
### The safe navigation operator ( ?. ) and null property paths
|
||||
|
||||
The Angular **Elvis operator (`?.`)** — perhaps better described as the "safe navigation operator" — is a fluent and convenient way to guard against null and undefined values in property paths.
|
||||
The Angular **safe navigation operator (`?.`)** is a fluent and convenient way to guard against null and undefined values in property paths.
|
||||
Here it is, protecting against a view render failure if the `currentHero` is null.
|
||||
// #enddocregion expression-operators-elvis-1
|
||||
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-2')(format=".")
|
||||
// #docregion expression-operators-elvis-2
|
||||
// #enddocregion expression-operators-safe-1
|
||||
+makeExample('template-syntax/ts/app/app.component.html', 'safe-2')(format=".")
|
||||
// #docregion expression-operators-safe-2
|
||||
:marked
|
||||
Let’s elaborate on the problem and this particular solution.
|
||||
|
||||
What happens when the following data bound `title` property is null?
|
||||
// #enddocregion expression-operators-elvis-2
|
||||
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-1')(format=".")
|
||||
// #docregion expression-operators-elvis-3
|
||||
// #enddocregion expression-operators-safe-2
|
||||
+makeExample('template-syntax/ts/app/app.component.html', 'safe-1')(format=".")
|
||||
// #docregion expression-operators-safe-3
|
||||
:marked
|
||||
The view still renders but the displayed value is blank; we see only "The title is" with nothing after it.
|
||||
That is reasonable behavior. At least the app doesn't crash.
|
||||
|
@ -1634,14 +1634,14 @@ figure.image-display
|
|||
|
||||
code-example(format="" language="html").
|
||||
The null hero's name is {{nullHero.firstName}}
|
||||
// #enddocregion expression-operators-elvis-3
|
||||
// #docregion expression-operators-elvis-4
|
||||
// #enddocregion expression-operators-safe-3
|
||||
// #docregion expression-operators-safe-4
|
||||
:marked
|
||||
JavaScript throws a null reference error, and so does Angular:
|
||||
code-example(format="" language="html").
|
||||
TypeError: Cannot read property 'firstName' of null in [null]
|
||||
// #enddocregion expression-operators-elvis-4
|
||||
// #docregion expression-operators-elvis-5
|
||||
// #enddocregion expression-operators-safe-4
|
||||
// #docregion expression-operators-safe-5
|
||||
:marked
|
||||
Worse, the *entire view disappears*.
|
||||
|
||||
|
@ -1659,30 +1659,30 @@ code-example(format="" language="html").
|
|||
Unfortunately, our app crashes when the `currentHero` is null.
|
||||
|
||||
We could code around that problem with [NgIf](#ngIf).
|
||||
// #enddocregion expression-operators-elvis-5
|
||||
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-4')(format=".")
|
||||
// #docregion expression-operators-elvis-6
|
||||
// #enddocregion expression-operators-safe-5
|
||||
+makeExample('template-syntax/ts/app/app.component.html', 'safe-4')(format=".")
|
||||
// #docregion expression-operators-safe-6
|
||||
:marked
|
||||
Or we could try to chain parts of the property path with `&&`, knowing that the expression bails out
|
||||
when it encounters the first null.
|
||||
// #enddocregion expression-operators-elvis-6
|
||||
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-5')(format=".")
|
||||
// #docregion expression-operators-elvis-7
|
||||
// #enddocregion expression-operators-safe-6
|
||||
+makeExample('template-syntax/ts/app/app.component.html', 'safe-5')(format=".")
|
||||
// #docregion expression-operators-safe-7
|
||||
:marked
|
||||
These approaches have 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`.
|
||||
// #enddocregion expression-operators-elvis-7
|
||||
// #docregion expression-operators-elvis-8
|
||||
// #enddocregion expression-operators-safe-7
|
||||
// #docregion expression-operators-safe-8
|
||||
:marked
|
||||
The Angular Elvis operator (`?.`) is a more fluent and convenient way to guard against nulls in property paths.
|
||||
The Angular safe navigation operator (`?.`) is a more fluent and convenient way to guard against nulls in property paths.
|
||||
The expression bails out when it hits the first null value.
|
||||
The display is blank, but the app keeps rolling without errors.
|
||||
// #enddocregion expression-operators-elvis-8
|
||||
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-6')(format=".")
|
||||
// #docregion expression-operators-elvis-9
|
||||
// #enddocregion expression-operators-safe-8
|
||||
+makeExample('template-syntax/ts/app/app.component.html', 'safe-6')(format=".")
|
||||
// #docregion expression-operators-safe-9
|
||||
:marked
|
||||
It works perfectly with long property paths such as `a?.b?.c?.d`.
|
||||
// #enddocregion expression-operators-elvis-9
|
||||
// #enddocregion expression-operators-safe-9
|
||||
|
||||
// #docregion summary
|
||||
.l-main-section
|
||||
|
|
|
@ -1655,7 +1655,7 @@ code-example(format="").
|
|||
a property expression, as opposed to a literal string.
|
||||
* We've replaced `ng-repeat`s with `*ngFor`s.
|
||||
* We've replaced `ng-click` with an event binding for the standard `click`.
|
||||
* In all references to `phone`, we're using the elvis operator `?.` for
|
||||
* In all references to `phone`, we're using the safe navigation operator `?.` for
|
||||
safe property navigation. We need it because when the component first loads,
|
||||
we don't have `phone` yet and the expressions will refer to a non-existing
|
||||
value. Unlike in Angular 1, Angular 2 expressions do not fail silently when
|
||||
|
|
Loading…
Reference in New Issue