chore: rename Elvis to safe navigation operator

closes #1139
This commit is contained in:
Foxandxss 2016-04-22 22:57:41 +02:00 committed by Ward Bell
parent 0e63b1f39b
commit 4097c67b59
5 changed files with 74 additions and 74 deletions

View File

@ -34,7 +34,7 @@
<a href="#local-vars">Template local variables</a><br> <a href="#local-vars">Template local variables</a><br>
<a href="#inputs-and-outputs">Inputs and outputs</a><br> <a href="#inputs-and-outputs">Inputs and outputs</a><br>
<a href="#pipes">Pipes</a><br> <a href="#pipes">Pipes</a><br>
<a href="#elvis">Elvis <i>?.</i></a><br> <a href="#safe-navigation-operator">Safe navigation operator <i>?.</i></a><br>
<!--<a href="#enums">Enums</a><br>--> <!--<a href="#enums">Enums</a><br>-->
<!-- Interpolation and expressions --> <!-- Interpolation and expressions -->
@ -738,25 +738,25 @@ bindon-ngModel
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>
<!-- Null values and the Elvis operator --> <!-- Null values and the safe navigation operator -->
<hr><h2 id="elvis">Elvis <i>?.</i></h2> <hr><h2 id="safe-navigation-operator">Safe navigation operator <i>?.</i></h2>
<div> <div>
<!-- #docregion elvis-1 --> <!-- #docregion safe-1 -->
The title is {{ title }} The title is {{ title }}
<!-- #enddocregion elvis-1 --> <!-- #enddocregion safe-1 -->
</div> </div>
<div> <div>
<!-- #docregion elvis-2 --> <!-- #docregion safe-2 -->
The current hero's name is {{currentHero?.firstName}} The current hero's name is {{currentHero?.firstName}}
<!-- #enddocregion elvis-2 --> <!-- #enddocregion safe-2 -->
</div> </div>
<div> <div>
<!-- #docregion elvis-3 --> <!-- #docregion safe-3 -->
The current hero's name is {{currentHero.firstName}} The current hero's name is {{currentHero.firstName}}
<!-- #enddocregion elvis-3 --> <!-- #enddocregion safe-3 -->
</div> </div>
@ -768,18 +768,18 @@ The null hero's name is {{nullHero.firstName}}
EXCEPTION: The null object does not have a getter 'firstName'. EXCEPTION: The null object does not have a getter 'firstName'.
--> -->
<!-- #docregion elvis-4 --> <!-- #docregion safe-4 -->
<!--No hero, div not displayed, no error --> <!--No hero, div not displayed, no error -->
<div *ngIf="nullHero != null">The null hero's name is {{nullHero.firstName}}</div> <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> <div>
<!-- #docregion elvis-6 --> <!-- #docregion safe-6 -->
<!-- No hero, no problem! --> <!-- No hero, no problem! -->
The null hero's name is {{nullHero?.firstName}} The null hero's name is {{nullHero?.firstName}}
<!-- #enddocregion elvis-6 --> <!-- #enddocregion safe-6 -->
</div> </div>

View File

@ -34,7 +34,7 @@
<a href="#local-vars">Template local variables</a><br> <a href="#local-vars">Template local variables</a><br>
<a href="#inputs-and-outputs">Inputs and outputs</a><br> <a href="#inputs-and-outputs">Inputs and outputs</a><br>
<a href="#pipes">Pipes</a><br> <a href="#pipes">Pipes</a><br>
<a href="#elvis">Elvis <i>?.</i></a><br> <a href="#safe-navigation-operator">Safe navigation operator <i>?.</i></a><br>
<a href="#enums">Enums</a><br> <a href="#enums">Enums</a><br>
<!-- Interpolation and expressions --> <!-- Interpolation and expressions -->
@ -739,25 +739,25 @@ After setClasses(), the classes are "{{classDiv.className}}"
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>
<!-- Null values and the Elvis operator --> <!-- Null values and the safe navigation operator -->
<hr><h2 id="elvis">Elvis <i>?.</i></h2> <hr><h2 id="safe-navigation-operator">Safe navigation operator <i>?.</i></h2>
<div> <div>
<!-- #docregion elvis-1 --> <!-- #docregion safe-1 -->
The title is {{ title }} The title is {{ title }}
<!-- #enddocregion elvis-1 --> <!-- #enddocregion safe-1 -->
</div> </div>
<div> <div>
<!-- #docregion elvis-2 --> <!-- #docregion safe-2 -->
The current hero's name is {{currentHero?.firstName}} The current hero's name is {{currentHero?.firstName}}
<!-- #enddocregion elvis-2 --> <!-- #enddocregion safe-2 -->
</div> </div>
<div> <div>
<!-- #docregion elvis-3 --> <!-- #docregion safe-3 -->
The current hero's name is {{currentHero.firstName}} The current hero's name is {{currentHero.firstName}}
<!-- #enddocregion elvis-3 --> <!-- #enddocregion safe-3 -->
</div> </div>
@ -768,22 +768,22 @@ See console log
TypeError: Cannot read property 'firstName' of null in [null] TypeError: Cannot read property 'firstName' of null in [null]
--> -->
<!-- #docregion elvis-4 --> <!-- #docregion safe-4 -->
<!--No hero, div not displayed, no error --> <!--No hero, div not displayed, no error -->
<div *ngIf="nullHero">The null hero's name is {{nullHero.firstName}}</div> <div *ngIf="nullHero">The null hero's name is {{nullHero.firstName}}</div>
<!-- #enddocregion elvis-4 --> <!-- #enddocregion safe-4 -->
<div> <div>
<!-- #docregion elvis-5 --> <!-- #docregion safe-5 -->
The null hero's name is {{nullHero && nullHero.firstName}} The null hero's name is {{nullHero && nullHero.firstName}}
<!-- #enddocregion elvis-5 --> <!-- #enddocregion safe-5 -->
</div> </div>
<div> <div>
<!-- #docregion elvis-6 --> <!-- #docregion safe-6 -->
<!-- No hero, no problem! --> <!-- No hero, no problem! -->
The null hero's name is {{nullHero?.firstName}} The null hero's name is {{nullHero?.firstName}}
<!-- #enddocregion elvis-6 --> <!-- #enddocregion safe-6 -->
</div> </div>

View File

@ -366,11 +366,11 @@ table
:marked :marked
## Template expression operators ## Template expression operators
The template expression language employs a subset of Dart syntax supplemented with a few special 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 .callout.is-helpful
header Dart difference: ?. is a Dart operator header Dart difference: ?. is a Dart operator
:marked :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 It's considered a template expression operator because
Angular 2 supports `?.` even in TypeScript and JavaScript apps. Angular 2 supports `?.` even in TypeScript and JavaScript apps.
+includeShared('{ts}', 'expression-operators-pipe-1') +includeShared('{ts}', 'expression-operators-pipe-1')
@ -383,28 +383,28 @@ table
NOTE: Intentionally omit discussion of the json pipe. NOTE: Intentionally omit discussion of the json pipe.
+includeShared('{ts}', 'expression-operators-pipe-4') +includeShared('{ts}', 'expression-operators-pipe-4')
+makeExample('template-syntax/dart/lib/app_component.html', 'pipes-json')(format=".") +makeExample('template-syntax/dart/lib/app_component.html', 'pipes-json')(format=".")
+includeShared('{ts}', 'expression-operators-elvis-1') +includeShared('{ts}', 'expression-operators-safe-1')
+makeExample('template-syntax/dart/lib/app_component.html', 'elvis-2')(format=".") +makeExample('template-syntax/dart/lib/app_component.html', 'safe-2')(format=".")
+includeShared('{ts}', 'expression-operators-elvis-2') +includeShared('{ts}', 'expression-operators-safe-2')
+makeExample('template-syntax/dart/lib/app_component.html', 'elvis-1')(format=".") +makeExample('template-syntax/dart/lib/app_component.html', 'safe-1')(format=".")
+includeShared('{ts}', 'expression-operators-elvis-3') +includeShared('{ts}', 'expression-operators-safe-3')
// +includeShared('{ts}', 'expression-operators-elvis-4') // +includeShared('{ts}', 'expression-operators-safe-4')
:marked :marked
Dart throws an exception, and so does Angular: Dart throws an exception, and so does Angular:
code-example(format="" language="html"). code-example(format="" language="html").
EXCEPTION: The null object does not have a getter 'firstName'. EXCEPTION: The null object does not have a getter 'firstName'.
+includeShared('{ts}', 'expression-operators-elvis-5') +includeShared('{ts}', 'expression-operators-safe-5')
+makeExample('template-syntax/dart/lib/app_component.html', 'elvis-4')(format=".") +makeExample('template-syntax/dart/lib/app_component.html', 'safe-4')(format=".")
// //
NOTE: Intentionally skip ugly null checking you wouldn't do in Dart. NOTE: Intentionally skip ugly null checking you wouldn't do in Dart.
That means skipping the shared sections 'expression-operators-elvis-6' & 7, That means skipping the shared sections 'expression-operators-safe-6' & 7,
plus the example 'elvis-5'. plus the example 'safe-5'.
:marked :marked
This approach has merit but can be cumbersome, especially if the property path is long. 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`. Imagine guarding against a null somewhere in a long property path such as `a.b.c.d`.
+includeShared('{ts}', 'expression-operators-elvis-8') +includeShared('{ts}', 'expression-operators-safe-8')
+makeExample('template-syntax/dart/lib/app_component.html', 'elvis-6')(format=".") +makeExample('template-syntax/dart/lib/app_component.html', 'safe-6')(format=".")
+includeShared('{ts}', 'expression-operators-elvis-9') +includeShared('{ts}', 'expression-operators-safe-9')
+includeShared('{ts}', 'summary') +includeShared('{ts}', 'summary')

View File

@ -28,7 +28,7 @@ include ../_util-fns
* [Input and output properties](#inputs-outputs) * [Input and output properties](#inputs-outputs)
* [Template expression operators](#expression-operators) * [Template expression operators](#expression-operators)
* [pipe](#pipe) * [pipe](#pipe)
* ["elvis" (?.)](#elvis) * ["safe navigation operator" (?.)](#safe-navigation-operator)
// #enddocregion intro // #enddocregion intro
.l-sub-section .l-sub-section
:marked :marked
@ -1576,7 +1576,7 @@ figure.image-display
:marked :marked
## Template expression operators ## Template expression operators
The template expression language employs a subset of JavaScript syntax supplemented with a few special 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 // #enddocregion expression-operators
// #docregion expression-operators-pipe-1 // #docregion expression-operators-pipe-1
@ -1608,23 +1608,23 @@ figure.image-display
// #enddocregion expression-operators-pipe-4 // #enddocregion expression-operators-pipe-4
+makeExample('template-syntax/ts/app/app.component.html', 'pipes-json')(format=".") +makeExample('template-syntax/ts/app/app.component.html', 'pipes-json')(format=".")
// #docregion expression-operators-elvis-1 // #docregion expression-operators-safe-1
:marked :marked
<a id="elvis"></a> <a id="safe-navigation-operator"></a>
### The Elvis operator ( ?. ) and null property paths ### The safe navigation operator ( ?. ) and null property paths
The Angular **Elvis operator (`?.`)** &mdash; perhaps better described as the "safe navigation operator" &mdash; 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. Here it is, protecting against a view render failure if the `currentHero` is null.
// #enddocregion expression-operators-elvis-1 // #enddocregion expression-operators-safe-1
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-2')(format=".") +makeExample('template-syntax/ts/app/app.component.html', 'safe-2')(format=".")
// #docregion expression-operators-elvis-2 // #docregion expression-operators-safe-2
:marked :marked
Lets elaborate on the problem and this particular solution. Lets elaborate on the problem and this particular solution.
What happens when the following data bound `title` property is null? What happens when the following data bound `title` property is null?
// #enddocregion expression-operators-elvis-2 // #enddocregion expression-operators-safe-2
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-1')(format=".") +makeExample('template-syntax/ts/app/app.component.html', 'safe-1')(format=".")
// #docregion expression-operators-elvis-3 // #docregion expression-operators-safe-3
:marked :marked
The view still renders but the displayed value is blank; we see only "The title is" with nothing after it. 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. That is reasonable behavior. At least the app doesn't crash.
@ -1634,14 +1634,14 @@ figure.image-display
code-example(format="" language="html"). code-example(format="" language="html").
The null hero's name is {{nullHero.firstName}} The null hero's name is {{nullHero.firstName}}
// #enddocregion expression-operators-elvis-3 // #enddocregion expression-operators-safe-3
// #docregion expression-operators-elvis-4 // #docregion expression-operators-safe-4
:marked :marked
JavaScript throws a null reference error, and so does Angular: JavaScript throws a null reference error, and so does Angular:
code-example(format="" language="html"). code-example(format="" language="html").
TypeError: Cannot read property 'firstName' of null in [null] TypeError: Cannot read property 'firstName' of null in [null]
// #enddocregion expression-operators-elvis-4 // #enddocregion expression-operators-safe-4
// #docregion expression-operators-elvis-5 // #docregion expression-operators-safe-5
:marked :marked
Worse, the *entire view disappears*. Worse, the *entire view disappears*.
@ -1659,30 +1659,30 @@ code-example(format="" language="html").
Unfortunately, our app crashes when the `currentHero` is null. Unfortunately, our app crashes when the `currentHero` is null.
We could code around that problem with [NgIf](#ngIf). We could code around that problem with [NgIf](#ngIf).
// #enddocregion expression-operators-elvis-5 // #enddocregion expression-operators-safe-5
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-4')(format=".") +makeExample('template-syntax/ts/app/app.component.html', 'safe-4')(format=".")
// #docregion expression-operators-elvis-6 // #docregion expression-operators-safe-6
:marked :marked
Or we could try to chain parts of the property path with `&&`, knowing that the expression bails out Or we could try to chain parts of the property path with `&&`, knowing that the expression bails out
when it encounters the first null. when it encounters the first null.
// #enddocregion expression-operators-elvis-6 // #enddocregion expression-operators-safe-6
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-5')(format=".") +makeExample('template-syntax/ts/app/app.component.html', 'safe-5')(format=".")
// #docregion expression-operators-elvis-7 // #docregion expression-operators-safe-7
:marked :marked
These approaches have merit but can be cumbersome, especially if the property path is long. 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`. Imagine guarding against a null somewhere in a long property path such as `a.b.c.d`.
// #enddocregion expression-operators-elvis-7 // #enddocregion expression-operators-safe-7
// #docregion expression-operators-elvis-8 // #docregion expression-operators-safe-8
:marked :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 expression bails out when it hits the first null value.
The display is blank, but the app keeps rolling without errors. The display is blank, but the app keeps rolling without errors.
// #enddocregion expression-operators-elvis-8 // #enddocregion expression-operators-safe-8
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-6')(format=".") +makeExample('template-syntax/ts/app/app.component.html', 'safe-6')(format=".")
// #docregion expression-operators-elvis-9 // #docregion expression-operators-safe-9
:marked :marked
It works perfectly with long property paths such as `a?.b?.c?.d`. 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 // #docregion summary
.l-main-section .l-main-section

View File

@ -1655,7 +1655,7 @@ code-example(format="").
a property expression, as opposed to a literal string. a property expression, as opposed to a literal string.
* We've replaced `ng-repeat`s with `*ngFor`s. * We've replaced `ng-repeat`s with `*ngFor`s.
* We've replaced `ng-click` with an event binding for the standard `click`. * 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, 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 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 value. Unlike in Angular 1, Angular 2 expressions do not fail silently when