diff --git a/aio/content/examples/template-expression-operators/e2e/src/app.e2e-spec.ts b/aio/content/examples/template-expression-operators/e2e/src/app.e2e-spec.ts
new file mode 100644
index 0000000000..bb5e8f4501
--- /dev/null
+++ b/aio/content/examples/template-expression-operators/e2e/src/app.e2e-spec.ts
@@ -0,0 +1,31 @@
+import { browser, element, by } from 'protractor';
+import { logging } from 'selenium-webdriver';
+
+describe('Template Expression Operators', function () {
+
+ beforeAll(function () {
+ browser.get('');
+ });
+
+ it('should have title Inputs and Outputs', function () {
+ let title = element.all(by.css('h1')).get(0);
+ expect(title.getText()).toEqual('Template Expression Operators');
+ });
+
+ it('should display json data', function () {
+ let jsonDate = element.all(by.css('p')).get(4);
+ expect(jsonDate.getText()).toContain('1980');
+ });
+
+ it('should display $98', function () {
+ let jsonDate = element.all(by.css('p')).get(5);
+ expect(jsonDate.getText()).toContain('$98.00');
+ });
+
+ it('should display Telephone', function () {
+ let jsonDate = element.all(by.css('p')).get(6);
+ expect(jsonDate.getText()).toContain('Telephone');
+ });
+
+
+});
diff --git a/aio/content/examples/template-expression-operators/example-config.json b/aio/content/examples/template-expression-operators/example-config.json
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/aio/content/examples/template-expression-operators/src/app/app.component.css b/aio/content/examples/template-expression-operators/src/app/app.component.css
new file mode 100644
index 0000000000..3e58f2fe73
--- /dev/null
+++ b/aio/content/examples/template-expression-operators/src/app/app.component.css
@@ -0,0 +1,10 @@
+.no-show-div {
+ background-color: #ecfdff;
+ border: 1px #444 solid;
+ padding: 1rem;
+ color: #444;
+}
+
+.error {
+ color: red;
+}
diff --git a/aio/content/examples/template-expression-operators/src/app/app.component.html b/aio/content/examples/template-expression-operators/src/app/app.component.html
new file mode 100644
index 0000000000..b2e04ec7d2
--- /dev/null
+++ b/aio/content/examples/template-expression-operators/src/app/app.component.html
@@ -0,0 +1,80 @@
+
{{title}}
+
+
+
+
Pipes
+
+
Title through uppercase pipe: {{title | uppercase}}
+
+
+
+
Title through a pipe chain: {{title | uppercase | lowercase}}
+
+
+
+
+
Manufacture date with date format pipe: {{item.manufactureDate | date:'longDate'}}
+
+
Manufacture date with uppercase pipe: {{(item.manufactureDate | date:'longDate') | uppercase}}
+
+
Item json pipe: {{item | json}}
+
+
+
+
Price with currency pipe: {{item.price | currency:'USD'}}
+
+
+
+
Safe navigation operator: ? and null
+
+
The item name is: {{item?.name}}
+
+
+
+
The nullItem name is: {{nullItem?.name}}
+
+
+
+
+
Error because nullItem is null:
+
+
+
+
+
Uncomment above paragraph and see console log for error about nullItem.name:
+
TypeError: Cannot read property 'name' of null
+
+
+
+
+
The div will not display and there's no error:
+
+
There's a child paragraph element in here that doesn't show.
+
The null item's name {{nullItem.name}}
+
+
+
+
Div shows but interpolation doesn't:
+
+
Using and (&&)
+
The null item's name is: {{nullItem && nullItem.name}}
+
+
+
+
Using safe navigation operator (?)
+
+
The null item's name is: {{nullItem?.name}}
+
+
+
+
+
+
Non-null assertion operator (!)
+
+
+
+
The item's color is: {{item!.color}}
+
+
+
+
diff --git a/aio/content/examples/template-expression-operators/src/app/app.component.spec.ts b/aio/content/examples/template-expression-operators/src/app/app.component.spec.ts
new file mode 100644
index 0000000000..bcbdf36b3e
--- /dev/null
+++ b/aio/content/examples/template-expression-operators/src/app/app.component.spec.ts
@@ -0,0 +1,27 @@
+import { TestBed, async } from '@angular/core/testing';
+import { AppComponent } from './app.component';
+describe('AppComponent', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ AppComponent
+ ],
+ }).compileComponents();
+ }));
+ it('should create the app', async(() => {
+ const fixture = TestBed.createComponent(AppComponent);
+ const app = fixture.debugElement.componentInstance;
+ expect(app).toBeTruthy();
+ }));
+ it(`should have as title 'app'`, async(() => {
+ const fixture = TestBed.createComponent(AppComponent);
+ const app = fixture.debugElement.componentInstance;
+ expect(app.title).toEqual('app');
+ }));
+ it('should render title in a h1 tag', async(() => {
+ const fixture = TestBed.createComponent(AppComponent);
+ fixture.detectChanges();
+ const compiled = fixture.debugElement.nativeElement;
+ expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
+ }));
+});
diff --git a/aio/content/examples/template-expression-operators/src/app/app.component.ts b/aio/content/examples/template-expression-operators/src/app/app.component.ts
new file mode 100644
index 0000000000..e0a6ddf2f5
--- /dev/null
+++ b/aio/content/examples/template-expression-operators/src/app/app.component.ts
@@ -0,0 +1,21 @@
+import { Component } from '@angular/core';
+
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ styleUrls: ['./app.component.css']
+})
+export class AppComponent {
+ title = 'Template Expression Operators';
+
+ item = {
+ name : 'Telephone',
+ manufactureDate : new Date(1980, 1, 25),
+ price: 98
+ };
+
+ nullItem = null;
+
+}
+
diff --git a/aio/content/examples/template-expression-operators/src/app/app.module.ts b/aio/content/examples/template-expression-operators/src/app/app.module.ts
new file mode 100644
index 0000000000..926975afe8
--- /dev/null
+++ b/aio/content/examples/template-expression-operators/src/app/app.module.ts
@@ -0,0 +1,18 @@
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+
+
+import { AppComponent } from './app.component';
+
+
+@NgModule({
+ declarations: [
+ AppComponent
+ ],
+ imports: [
+ BrowserModule
+ ],
+ providers: [],
+ bootstrap: [AppComponent]
+})
+export class AppModule { }
diff --git a/aio/content/examples/template-expression-operators/src/index.html b/aio/content/examples/template-expression-operators/src/index.html
new file mode 100644
index 0000000000..30c82e152b
--- /dev/null
+++ b/aio/content/examples/template-expression-operators/src/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+ Template Expression Operators Example
+
+
+
+
+
+
+ Loading...
+
+
diff --git a/aio/content/examples/template-expression-operators/src/main.ts b/aio/content/examples/template-expression-operators/src/main.ts
new file mode 100644
index 0000000000..a9ca1caf8c
--- /dev/null
+++ b/aio/content/examples/template-expression-operators/src/main.ts
@@ -0,0 +1,11 @@
+import { enableProdMode } from '@angular/core';
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+
+import { AppModule } from './app/app.module';
+import { environment } from './environments/environment';
+
+if (environment.production) {
+ enableProdMode();
+}
+
+platformBrowserDynamic().bootstrapModule(AppModule);
diff --git a/aio/content/examples/template-expression-operators/stackblitz.json b/aio/content/examples/template-expression-operators/stackblitz.json
new file mode 100644
index 0000000000..9b21040545
--- /dev/null
+++ b/aio/content/examples/template-expression-operators/stackblitz.json
@@ -0,0 +1,10 @@
+{
+ "description": "Template Expression Operators",
+ "files": [
+ "!**/*.d.ts",
+ "!**/*.js",
+ "!**/*.[1,2].*"
+ ],
+ "file": "src/app/app.component.ts",
+ "tags": ["Template Expression Operators"]
+}
diff --git a/aio/content/guide/template-syntax.md b/aio/content/guide/template-syntax.md
index 487912e4ec..8165cf751c 100644
--- a/aio/content/guide/template-syntax.md
+++ b/aio/content/guide/template-syntax.md
@@ -2121,119 +2121,93 @@ You can specify the alias for the property name by passing the alias name to the
## Template expression operators
-The template expression language employs a subset of JavaScript syntax supplemented with a few special operators
-for specific scenarios. The next sections cover two of these operators: _pipe_ and _safe navigation operator_.
+The Angular template expression language employs a subset of JavaScript syntax supplemented with a few special operators
+for specific scenarios. The next sections cover three of these operators:
+
+* [pipe](guide/template-syntax#pipe)
+* [safe navigation operator](guide/template-syntax#safe-navigation-operator)
+* [non-null assertion operator](guide/template-syntax#non-null-assertion-operator)
{@a pipe}
-### The pipe operator ( | )
+### The pipe operator (`|`)
The result of an expression might require some transformation before you're ready to use it in a binding.
-For example, you might display a number as a currency, force text to uppercase, or filter a list and sort it.
+For example, you might display a number as a currency, change text to uppercase, or filter a list and sort it.
-Angular [pipes](guide/pipes) are a good choice for small transformations such as these.
Pipes are simple functions that accept an input value and return a transformed value.
-They're easy to apply within template expressions, using the **pipe operator (`|`)**:
+They're easy to apply within template expressions, using the pipe operator (`|`):
-
+
The pipe operator passes the result of an expression on the left to a pipe function on the right.
You can chain expressions through multiple pipes:
-
+
And you can also [apply parameters](guide/pipes#parameterizing-a-pipe) to a pipe:
-
+
The `json` pipe is particularly helpful for debugging bindings:
-
+
-The generated output would look something like this
+The generated output would look something like this:
- { "id": 0, "name": "Hercules", "emotion": "happy",
- "birthdate": "1970-02-25T08:00:00.000Z",
- "url": "http://www.imdb.com/title/tt0065832/",
- "rate": 325 }
+ { "name": "Telephone",
+ "manufactureDate": "1980-02-25T05:00:00.000Z",
+ "price": 98 }
+
+
+**Note**: The pipe operator has a higher precedence than the ternary operator (`?:`),
+which means `a ? b : c | x` is parsed as `a ? b : (c | x)`.
+Nevertheless, for a number of reasons,
+the pipe operator cannot be used without parentheses in the first and second operands of `?:`.
+A good practice is to use parentheses in the third operand too.
+
+
+
{@a safe-navigation-operator}
-### The safe navigation operator ( ?. ) and null property paths
+### The safe navigation operator ( `?` ) and null 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.
+The Angular safe navigation operator, `?`, guards against `null` and `undefined`
+values in property paths. Here, it protects against a view render failure if `item` is `null`.
-
+
-What happens when the following data bound `title` property is null?
+If `item` is `null`, the view still renders but the displayed value is blank; you see only "The item name is:" with nothing after it.
-
-
-
-The view still renders but the displayed value is blank; you see only "The title is" with nothing after it.
-That is reasonable behavior. At least the app doesn't crash.
-
-Suppose the template expression involves a property path, as in this next example
-that displays the `name` of a null hero.
+Consider the next example, with a `nullItem`.
- The null hero's name is {{nullHero.name}}
+ The null item name is {{nullItem.name}}
-JavaScript throws a null reference error, and so does Angular:
+Since there is no safe navigation operator and `nullItem` is `null`, JavaScript and Angular would throw a `null` reference error and break the rendering process of Angular:
- TypeError: Cannot read property 'name' of null in [null].
+ TypeError: Cannot read property 'name' of null.
-Worse, the *entire view disappears*.
+Sometimes however, `null` values in the property
+path may be OK under certain circumstances,
+especially when the value starts out null but the data arrives eventually.
-This would be reasonable behavior if the `hero` property could never be null.
-If it must never be null and yet it is null,
-that's a programming error that should be caught and fixed.
-Throwing an exception is the right thing to do.
-
-On the other hand, null values in the property path may be OK from time to time,
-especially when the data are null now and will arrive eventually.
-
-While waiting for data, the view should render without complaint, and
-the null property path should display as blank just as the `title` property does.
-
-Unfortunately, the app crashes when the `currentHero` is null.
-
-You could code around that problem with [*ngIf](guide/template-syntax#ngIf).
-
-
-
-
-You could try to chain parts of the property path with `&&`, knowing that the expression bails out
-when it encounters the first null.
-
-
-
-
-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`.
-
-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.
-
-
-
+With the safe navigation operator, `?`, Angular stops evaluating the expression when it hits the first `null` value and renders the view without errors.
It works perfectly with long property paths such as `a?.b?.c?.d`.
@@ -2242,34 +2216,31 @@ It works perfectly with long property paths such as `a?.b?.c?.d`.
{@a non-null-assertion-operator}
-### The non-null assertion operator ( ! )
+### The non-null assertion operator ( `!` )
-As of Typescript 2.0, you can enforce [strict null checking](http://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html "Strict null checking in TypeScript") with the `--strictNullChecks` flag. TypeScript then ensures that no variable is _unintentionally_ null or undefined.
+As of Typescript 2.0, you can enforce [strict null checking](http://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html "Strict null checking in TypeScript") with the `--strictNullChecks` flag. TypeScript then ensures that no variable is unintentionally null or undefined.
-In this mode, typed variables disallow null and undefined by default. The type checker throws an error if you leave a variable unassigned or try to assign null or undefined to a variable whose type disallows null and undefined.
+In this mode, typed variables disallow `null` and `undefined` by default. The type checker throws an error if you leave a variable unassigned or try to assign `null` or `undefined` to a variable whose type disallows `null` and `undefined`.
-The type checker also throws an error if it can't determine whether a variable will be null or undefined at runtime.
-You may know that can't happen but the type checker doesn't know.
-You tell the type checker that it can't happen by applying the post-fix
-[_non-null assertion operator (!)_](http://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#non-null-assertion-operator "Non-null assertion operator").
+The type checker also throws an error if it can't determine whether a variable will be `null` or undefined at runtime. You tell the type checker not to throw an error by applying the postfix
+[non-null assertion operator, !](http://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#non-null-assertion-operator "Non-null assertion operator").
-The _Angular_ **non-null assertion operator (`!`)** serves the same purpose in an Angular template.
+The Angular non-null assertion operator, `!`, serves the same purpose in
+an Angular template. For example, after you use [*ngIf](guide/template-syntax#ngIf)
+to check that `item` is defined, you can assert that
+`item` properties are also defined.
-For example, after you use [*ngIf](guide/template-syntax#ngIf) to check that `hero` is defined, you can assert that
-`hero` properties are also defined.
-
-
+
When the Angular compiler turns your template into TypeScript code,
-it prevents TypeScript from reporting that `hero.name` might be null or undefined.
+it prevents TypeScript from reporting that `item` might be `null` or `undefined`.
-Unlike the [_safe navigation operator_](guide/template-syntax#safe-navigation-operator "Safe navigation operator (?.)"),
-the **non-null assertion operator** does not guard against null or undefined.
-Rather it tells the TypeScript type checker to suspend strict null checks for a specific property expression.
-
-You'll need this template operator when you turn on strict null checks. It's optional otherwise.
+Unlike the [_safe navigation operator_](guide/template-syntax#safe-navigation-operator "Safe navigation operator (?)"),
+the non-null assertion operator does not guard against `null` or `undefined`.
+Rather, it tells the TypeScript type checker to suspend strict `null` checks for a specific property expression.
+The non-null assertion operator, `!`, is optional with the exception that you must use it when you turn on strict null checks.
back to top