Structural Directives
Structural directives are responsible for HTML layout. They shape or reshape the DOM's structure, typically by adding, removing, or manipulating elements.
How Structural Directives Work
Structural directives use a * prefix on an element. AngularDart desugars this into
an <ng-template> wrapper:
<!-- Shorthand -->
<div *ngIf="user">Hello, {{ user.name }}</div>
<!-- Desugared -->
<ng-template [ngIf]="user">
<div>Hello, {{ user.name }}</div>
</ng-template>
*ngIf
Conditionally includes a template based on the truthiness of an expression.
Basic usage
<div *ngIf="isVisible">This is visible</div>
With else clause
<div *ngIf="user; else noUser">
Hello, {{ user.name }}
</div>
<ng-template #noUser>
<p>Please log in.</p>
</ng-template>
With then and else
<div *ngIf="isLoggedIn; then loggedIn; else loggedOut"></div>
<ng-template #loggedIn><p>Welcome back!</p></ng-template>
<ng-template #loggedOut><p>Please sign in.</p></ng-template>
Truthy and falsy values
In Dart, only null and false are falsy. All other values (including 0 and '')
are truthy.
<!-- All of these are truthy -->
<div *ngIf="1">Shows</div>
<div *ngIf="'hello'">Shows</div>
<div *ngIf="[]">Shows</div>
<!-- These are falsy -->
<div *ngIf="null">Hidden</div>
<div *ngIf="false">Hidden</div>
*ngFor
Renders a template for each item in a collection.
Basic usage
<li *ngFor="let item of items">{{ item.name }}</li>
Template context variables
<li *ngFor="let item of items;
let i = index;
let isFirst = first;
let isLast = last;
let isEven = even;
let isOdd = odd;
let total = count">
{{ i + 1 }}/{{ total }}. {{ item.name }}
<span *ngIf="isFirst">(first)</span>
<span *ngIf="isLast">(last)</span>
</li>
Track by function
Use trackBy to optimize re-rendering when the collection changes:
<li *ngFor="let item of items; trackBy: trackById">{{ item.name }}</li>
dynamic trackById(int index, dynamic item) => item.id;
Empty template
Use *ngIf with *ngFor to handle empty collections:
<ul *ngIf="items.isNotEmpty; else emptyList">
<li *ngFor="let item of items">{{ item.name }}</li>
</ul>
<ng-template #emptyList>
<p>No items found.</p>
</ng-template>
*ngSwitch
Conditionally swaps elements based on a switch expression.
<div [ngSwitch]="transportState">
<app-urgent-component *ngSwitchCase="'urgent'"></app-urgent-component>
<app-happy-component *ngSwitchCase="'happy'"></app-happy-component>
<app-normal-component *ngSwitchCase="'normal'"></app-normal-component>
<app-unknown-component *ngSwitchDefault></app-unknown-component>
</div>
Creating Custom Structural Directives
@Directive(
selector: '[myUnless]',
)
class MyUnlessDirective {
final ViewContainerRef _viewContainer;
final TemplateRef _templateRef;
bool _condition = false;
MyUnlessDirective(this._viewContainer, this._templateRef);
@Input()
set myUnless(bool condition) {
_condition = condition;
if (!_condition) {
_viewContainer.createEmbeddedView(_templateRef);
} else {
_viewContainer.clear();
}
}
}
Usage:
<p *myUnless="isHidden">This paragraph is displayed when isHidden is false.</p>
ng-template
Use <ng-template> to define a template that is not rendered by default:
<ng-template #myTemplate>
<p>This is a template</p>
</ng-template>
<ng-container *ngTemplateOutlet="myTemplate"></ng-container>
ng-container
<ng-container> is a grouping element that doesn't interfere with styles or layout
because AngularDart doesn't put it in the DOM:
<p>
I turned the corner
<ng-container *ngIf="hero">
and saw {{ hero.name }}. I waved
</ng-container>
and continued on my way.
</p>