2016-06-23 09:47:54 -07:00
|
|
|
/**
|
|
|
|
* @license
|
|
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
|
|
* found in the LICENSE file at https://angular.io/license
|
|
|
|
*/
|
|
|
|
|
2016-12-07 21:41:27 -08:00
|
|
|
import {Directive, EmbeddedViewRef, Input, TemplateRef, ViewContainerRef} from '@angular/core';
|
|
|
|
|
2016-06-08 16:38:52 -07:00
|
|
|
|
2015-03-31 22:47:11 +00:00
|
|
|
/**
|
2016-12-07 21:41:27 -08:00
|
|
|
* Conditionally includes a template based on the value of an `expression`.
|
|
|
|
*
|
|
|
|
* `ngIf` evaluates the `expression` and then renders the `then` or `else` template in its place
|
2016-12-22 22:36:47 +02:00
|
|
|
* when expression is truthy or falsy respectively. Typically the:
|
2016-12-07 21:41:27 -08:00
|
|
|
* - `then` template is the inline template of `ngIf` unless bound to a different value.
|
2016-12-22 22:36:47 +02:00
|
|
|
* - `else` template is blank unless it is bound.
|
2016-12-07 21:41:27 -08:00
|
|
|
*
|
|
|
|
* # Most common usage
|
|
|
|
*
|
2016-12-22 22:36:47 +02:00
|
|
|
* The most common usage of the `ngIf` directive is to conditionally show the inline template as
|
|
|
|
* seen in this example:
|
2016-12-07 21:41:27 -08:00
|
|
|
* {@example common/ngIf/ts/module.ts region='NgIfSimple'}
|
|
|
|
*
|
|
|
|
* # Showing an alternative template using `else`
|
|
|
|
*
|
|
|
|
* If it is necessary to display a template when the `expression` is falsy use the `else` template
|
2017-01-09 13:16:46 -08:00
|
|
|
* binding as shown. Note that the `else` binding points to a `<ng-template>` labeled `#elseBlock`.
|
2016-12-07 21:41:27 -08:00
|
|
|
* The template can be defined anywhere in the component view but is typically placed right after
|
|
|
|
* `ngIf` for readability.
|
|
|
|
*
|
|
|
|
* {@example common/ngIf/ts/module.ts region='NgIfElse'}
|
|
|
|
*
|
|
|
|
* # Using non-inlined `then` template
|
|
|
|
*
|
|
|
|
* Usually the `then` template is the inlined template of the `ngIf`, but it can be changed using
|
|
|
|
* a binding (just like `else`). Because `then` and `else` are bindings, the template references can
|
2016-12-22 22:36:47 +02:00
|
|
|
* change at runtime as shown in this example.
|
2015-04-10 11:15:01 -07:00
|
|
|
*
|
2016-12-07 21:41:27 -08:00
|
|
|
* {@example common/ngIf/ts/module.ts region='NgIfThenElse'}
|
2015-04-06 11:47:38 +02:00
|
|
|
*
|
2016-12-07 21:41:27 -08:00
|
|
|
* # Storing conditional result in a variable
|
|
|
|
*
|
2016-12-22 22:36:47 +02:00
|
|
|
* A common pattern is that we need to show a set of properties from the same object. If the
|
2016-12-07 21:41:27 -08:00
|
|
|
* object is undefined, then we have to use the safe-traversal-operator `?.` to guard against
|
|
|
|
* dereferencing a `null` value. This is especially the case when waiting on async data such as
|
|
|
|
* when using the `async` pipe as shown in folowing example:
|
2015-04-06 11:47:38 +02:00
|
|
|
*
|
|
|
|
* ```
|
2016-12-07 21:41:27 -08:00
|
|
|
* Hello {{ (userStream|async)?.last }}, {{ (userStream|async)?.first }}!
|
2015-04-06 11:47:38 +02:00
|
|
|
* ```
|
|
|
|
*
|
2016-12-22 22:36:47 +02:00
|
|
|
* There are several inefficiencies in the above example:
|
|
|
|
* - We create multiple subscriptions on `userStream`. One for each `async` pipe, or two in the
|
|
|
|
* example above.
|
|
|
|
* - We cannot display an alternative screen while waiting for the data to arrive asynchronously.
|
2016-12-07 21:41:27 -08:00
|
|
|
* - We have to use the safe-traversal-operator `?.` to access properties, which is cumbersome.
|
|
|
|
* - We have to place the `async` pipe in parenthesis.
|
|
|
|
*
|
|
|
|
* A better way to do this is to use `ngIf` and store the result of the condition in a local
|
|
|
|
* variable as shown in the the example below:
|
|
|
|
*
|
|
|
|
* {@example common/ngIf/ts/module.ts region='NgIfLet'}
|
|
|
|
*
|
|
|
|
* Notice that:
|
|
|
|
* - We use only one `async` pipe and hence only one subscription gets created.
|
|
|
|
* - `ngIf` stores the result of the `userStream|async` in the local variable `user`.
|
2016-12-22 22:36:47 +02:00
|
|
|
* - The local `user` can then be bound repeatedly in a more efficient way.
|
2016-12-07 21:41:27 -08:00
|
|
|
* - No need to use the safe-traversal-operator `?.` to access properties as `ngIf` will only
|
|
|
|
* display the data if `userStream` returns a value.
|
|
|
|
* - We can display an alternative template while waiting for the data.
|
|
|
|
*
|
2015-11-17 09:41:31 -08:00
|
|
|
* ### Syntax
|
2015-04-06 11:47:38 +02:00
|
|
|
*
|
2016-12-07 21:41:27 -08:00
|
|
|
* Simple form:
|
2015-11-23 16:02:19 -08:00
|
|
|
* - `<div *ngIf="condition">...</div>`
|
|
|
|
* - `<div template="ngIf condition">...</div>`
|
2017-01-09 13:16:46 -08:00
|
|
|
* - `<ng-template [ngIf]="condition"><div>...</div></ng-template>`
|
2016-12-07 21:41:27 -08:00
|
|
|
*
|
|
|
|
* Form with an else block:
|
|
|
|
* ```
|
|
|
|
* <div *ngIf="condition; else elseBlock">...</div>
|
2017-01-09 13:16:46 -08:00
|
|
|
* <ng-template #elseBlock>...</ng-template>
|
2016-12-07 21:41:27 -08:00
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* Form with a `then` and `else` block:
|
|
|
|
* ```
|
|
|
|
* <div *ngIf="condition; then thenBlock else elseBlock"></div>
|
2017-01-09 13:16:46 -08:00
|
|
|
* <ng-template #thenBlock>...</ng-template>
|
|
|
|
* <ng-template #elseBlock>...</ng-template>
|
2016-12-07 21:41:27 -08:00
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* Form with storing the value locally:
|
|
|
|
* ```
|
|
|
|
* <div *ngIf="condition; else elseBlock; let value">{{value}}</div>
|
2017-01-09 13:16:46 -08:00
|
|
|
* <ng-template #elseBlock>...</ng-template>
|
2016-12-07 21:41:27 -08:00
|
|
|
* ```
|
2016-05-27 11:24:05 -07:00
|
|
|
*
|
|
|
|
* @stable
|
2015-03-31 22:47:11 +00:00
|
|
|
*/
|
2016-07-07 16:35:13 -07:00
|
|
|
@Directive({selector: '[ngIf]'})
|
2015-05-11 15:58:59 -07:00
|
|
|
export class NgIf {
|
2016-12-07 21:41:27 -08:00
|
|
|
private _context: NgIfContext = new NgIfContext();
|
|
|
|
private _thenTemplateRef: TemplateRef<NgIfContext> = null;
|
|
|
|
private _elseTemplateRef: TemplateRef<NgIfContext> = null;
|
|
|
|
private _thenViewRef: EmbeddedViewRef<NgIfContext> = null;
|
|
|
|
private _elseViewRef: EmbeddedViewRef<NgIfContext> = null;
|
2014-12-17 10:01:08 +01:00
|
|
|
|
2016-12-07 21:41:27 -08:00
|
|
|
constructor(private _viewContainer: ViewContainerRef, templateRef: TemplateRef<NgIfContext>) {
|
|
|
|
this._thenTemplateRef = templateRef;
|
|
|
|
}
|
2014-12-17 10:01:08 +01:00
|
|
|
|
2016-07-07 16:35:13 -07:00
|
|
|
@Input()
|
2016-09-08 19:25:25 -07:00
|
|
|
set ngIf(condition: any) {
|
2016-12-07 21:41:27 -08:00
|
|
|
this._context.$implicit = condition;
|
|
|
|
this._updateView();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Input()
|
|
|
|
set ngIfThen(templateRef: TemplateRef<NgIfContext>) {
|
|
|
|
this._thenTemplateRef = templateRef;
|
|
|
|
this._thenViewRef = null; // clear previous view if any.
|
|
|
|
this._updateView();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Input()
|
|
|
|
set ngIfElse(templateRef: TemplateRef<NgIfContext>) {
|
|
|
|
this._elseTemplateRef = templateRef;
|
|
|
|
this._elseViewRef = null; // clear previous view if any.
|
|
|
|
this._updateView();
|
|
|
|
}
|
|
|
|
|
|
|
|
private _updateView() {
|
|
|
|
if (this._context.$implicit) {
|
|
|
|
if (!this._thenViewRef) {
|
|
|
|
this._viewContainer.clear();
|
|
|
|
this._elseViewRef = null;
|
|
|
|
if (this._thenTemplateRef) {
|
|
|
|
this._thenViewRef =
|
|
|
|
this._viewContainer.createEmbeddedView(this._thenTemplateRef, this._context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!this._elseViewRef) {
|
|
|
|
this._viewContainer.clear();
|
|
|
|
this._thenViewRef = null;
|
|
|
|
if (this._elseTemplateRef) {
|
|
|
|
this._elseViewRef =
|
|
|
|
this._viewContainer.createEmbeddedView(this._elseTemplateRef, this._context);
|
|
|
|
}
|
|
|
|
}
|
2014-12-17 10:01:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-12-07 21:41:27 -08:00
|
|
|
|
|
|
|
export class NgIfContext { public $implicit: any = null; }
|