Built-in directives
Use Angular's built-in directives to manage forms, lists, styles, and what users see.
The different types of Angular directives are as follows:
| Directive Types | Details |
|---|---|
| Components | Used with a template. This type of directive is the most common directive type. |
| Attribute directives | Change the appearance or behavior of an element, component, or another directive. |
| Structural directives | Change the DOM layout by adding and removing DOM elements. |
This guide covers built-in attribute directives.
Built-in attribute directives
Attribute directives listen to and modify the behavior of other HTML elements, attributes, properties, and components.
The most common attribute directives are as follows:
| Common directives | Details |
|---|---|
NgClass | Adds and removes a set of CSS classes. |
NgStyle | Adds and removes a set of HTML styles. |
NgModel | Adds two-way data binding to an HTML form element. |
Adding and removing classes with NgClass
Add or remove multiple CSS classes simultaneously with ngClass.
Import NgClass in the component
To use NgClass, add it to the component's imports list.
import {NgClass} from '@angular/common';
@Component({
/* ... */
imports: [NgClass],
})
export class AppComponent {}Using NgClass with an expression
On the element you'd like to style, add [ngClass] and set it equal to an expression. In this case, isSpecial is a boolean set to true in app.component.ts. Because isSpecial is true, ngClass applies the class of special to the <div>.
<h1>Built-in Directives</h1>
<h2>Built-in attribute directives</h2>
<h3 id="ngModel">NgModel (two-way) Binding</h3>
<fieldset>
<h4>NgModel examples</h4>
<p>Current item name: {{ currentItem.name }}</p>
<p>
<label for="without">without NgModel:</label>
<input [value]="currentItem.name" (input)="currentItem.name = getValue($event)" id="without" />
</p>
<p>
<!-- #docregion NgModel-1 -->
<label for="example-ngModel">[(ngModel)]:</label>
<input [(ngModel)]="currentItem.name" id="example-ngModel" />
<!-- #enddocregion NgModel-1 -->
</p>
<p>
<label for="example-change">(ngModelChange)="...name=$event":</label>
<input
[ngModel]="currentItem.name"
(ngModelChange)="currentItem.name = $event"
id="example-change"
/>
</p>
<p>
<label for="example-uppercase"
>(ngModelChange)="setUppercaseName($event)"
<!-- #docregion uppercase -->
<input
[ngModel]="currentItem.name"
(ngModelChange)="setUppercaseName($event)"
id="example-uppercase"
/>
<!-- #enddocregion uppercase -->
</label>
</p>
</fieldset>
<hr />
<h2 id="ngClass">NgClass Binding</h2>
<p>currentClasses is {{ currentClasses | json }}</p>
<!-- #docregion NgClass-1 -->
<div [ngClass]="currentClasses">This div is initially saveable, unchanged, and special.</div>
<!-- #enddocregion NgClass-1 -->
<ul>
<li>
<label for="saveable">saveable</label>
<input type="checkbox" [(ngModel)]="canSave" id="saveable" />
</li>
<li>
<label for="modified">modified:</label>
<input
type="checkbox"
[value]="!isUnchanged"
(change)="isUnchanged = !isUnchanged"
id="modified"
/>
</li>
<li>
<label for="special"
>special: <input type="checkbox" [(ngModel)]="isSpecial" id="special"
/></label>
</li>
</ul>
<button type="button" (click)="setCurrentClasses()">Refresh currentClasses</button>
<div [ngClass]="currentClasses">
This div should be {{ canSave ? '' : 'not' }} saveable,
{{ isUnchanged ? 'unchanged' : 'modified' }} and {{ isSpecial ? '' : 'not' }} special after
clicking "Refresh".
</div>
<br /><br />
<!-- #docregion special-div -->
<!-- toggle the "special" class on/off with a property -->
<div [ngClass]="isSpecial ? 'special' : ''">This div is special</div>
<!-- #enddocregion special-div -->
<div class="helpful study course">Helpful study course</div>
<div [ngClass]="{'helpful': false, 'study': true, 'course': true}">Study course</div>
<!-- NgStyle binding -->
<hr />
<h3>NgStyle Binding</h3>
<div [style.font-size]="isSpecial ? 'x-large' : 'smaller'">This div is x-large or smaller.</div>
<h4>[ngStyle] binding to currentStyles - CSS property names</h4>
<p>currentStyles is {{ currentStyles | json }}</p>
<!-- #docregion NgStyle-2 -->
<div [ngStyle]="currentStyles">
This div is initially italic, normal weight, and extra large (24px).
</div>
<!-- #enddocregion NgStyle-2 -->
<br />
<label for="canSave">italic: <input id="canSave" type="checkbox" [(ngModel)]="canSave" /></label> |
<label for="isUnchanged"
>normal: <input id="isUnchanged" type="checkbox" [(ngModel)]="isUnchanged"
/></label>
|
<label for="isSpecial"
>xlarge: <input id="isSpecial" type="checkbox" [(ngModel)]="isSpecial"
/></label>
<button type="button" (click)="setCurrentStyles()">Refresh currentStyles</button>
<br /><br />
<div [ngStyle]="currentStyles">
This div should be {{ canSave ? 'italic' : 'plain' }},
{{ isUnchanged ? 'normal weight' : 'bold' }} and,
{{ isSpecial ? 'extra large' : 'normal size' }} after clicking "Refresh".
</div>
<hr />
<h2>Built-in structural directives</h2>
<h3 id="ngIf">NgIf Binding</h3>
<div>
<p>If isActive is true, app-item-detail will render:</p>
<!-- #docregion NgIf-1 -->
<app-item-detail *ngIf="isActive" [item]="item"></app-item-detail>
<!-- #enddocregion NgIf-1 -->
<button type="button" (click)="isActiveToggle()">Toggle app-item-detail</button>
</div>
<p>If currentCustomer isn't null, say hello to Laura:</p>
<!-- #docregion NgIf-2 -->
<div *ngIf="currentCustomer">Hello, {{ currentCustomer.name }}</div>
<!-- #enddocregion NgIf-2 -->
<p>nullCustomer is null by default. NgIf guards against null. Give it a value to show it:</p>
<!-- #docregion NgIf-2b -->
<div *ngIf="nullCustomer">
Hello, <span>{{ nullCustomer }}</span>
</div>
<!-- #enddocregion NgIf-2b -->
<button type="button" (click)="giveNullCustomerValue()">Give nullCustomer a value</button>
<h4>NgIf binding with template (no *)</h4>
<ng-template [ngIf]="currentItem">Add {{ currentItem.name }} with template</ng-template>
<hr />
<h4>Show/hide vs. NgIf</h4>
<!-- isSpecial is true -->
<div [class.hidden]="!isSpecial">Show with class</div>
<div [class.hidden]="isSpecial">Hide with class</div>
<p>ItemDetail is in the DOM but hidden</p>
<app-item-detail [class.hidden]="isSpecial"></app-item-detail>
<div [style.display]="isSpecial ? 'block' : 'none'">Show with style</div>
<div [style.display]="isSpecial ? 'none' : 'block'">Hide with style</div>
<hr />
<h2 id="ngFor">NgFor Binding</h2>
<div class="box">
<!-- #docregion NgFor-1, NgFor-1-2 -->
<div *ngFor="let item of items">{{ item.name }}</div>
<!-- #enddocregion NgFor-1, NgFor-1-2 -->
</div>
<p>*ngFor with ItemDetailComponent element</p>
<div class="box">
<!-- #docregion NgFor-2, NgFor-1-2 -->
<app-item-detail *ngFor="let item of items" [item]="item"></app-item-detail>
<!-- #enddocregion NgFor-2, NgFor-1-2 -->
</div>
<h4 id="ngFor-index">*ngFor with index</h4>
<p>with <em>semi-colon</em> separator</p>
<div class="box">
<!-- #docregion NgFor-3 -->
<div *ngFor="let item of items; let i = index">{{ i + 1 }} - {{ item.name }}</div>
<!-- #enddocregion NgFor-3 -->
</div>
<p>with <em>comma</em> separator</p>
<div class="box">
<div *ngFor="let item of items; let i = index">{{ i + 1 }} - {{ item.name }}</div>
</div>
<h4 id="ngFor-trackBy">*ngFor trackBy</h4>
<button type="button" (click)="resetList()">Reset items</button>
<button type="button" (click)="changeIds()">Change ids</button>
<button type="button" (click)="clearTrackByCounts()">Clear counts</button>
<p><em>without</em> trackBy</p>
<div class="box">
<div #noTrackBy *ngFor="let item of items">({{ item.id }}) {{ item.name }}</div>
<div id="noTrackByCnt" *ngIf="itemsNoTrackByCount">
Item DOM elements change #{{ itemsNoTrackByCount }} without trackBy
</div>
</div>
<p>with trackBy</p>
<div class="box">
<div #withTrackBy *ngFor="let item of items; trackBy: trackByItems">
({{ item.id }}) {{ item.name }}
</div>
<div id="withTrackByCnt" *ngIf="itemsWithTrackByCount">
Item DOM elements change #{{ itemsWithTrackByCount }} with trackBy
</div>
</div>
<br /><br /><br />
<p>with trackBy and <em>semi-colon</em> separator</p>
<div class="box">
<!-- #docregion trackBy -->
<div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
<!-- #enddocregion trackBy -->
</div>
<p>with trackBy and <em>comma</em> separator</p>
<div class="box">
<div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
</div>
<p>with trackBy and <em>space</em> separator</p>
<div class="box">
<div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
</div>
<p>with <em>generic</em> trackById function</p>
<div class="box">
<div *ngFor="let item of items; trackBy: trackById">({{ item.id }}) {{ item.name }}</div>
</div>
<hr />
<h2>NgSwitch Binding</h2>
<p>Pick your favorite item</p>
<div>
<label for="item-{{ i }}" *ngFor="let i of items">
<div>
<input id="item-{{ i }}" type="radio" name="items" [(ngModel)]="currentItem" [value]="i" />{{
i.name
}}
</div>
</label>
</div>
<!-- #docregion NgSwitch -->
<div [ngSwitch]="currentItem.feature">
<app-stout-item *ngSwitchCase="'stout'" [item]="currentItem"></app-stout-item>
<app-device-item *ngSwitchCase="'slim'" [item]="currentItem"></app-device-item>
<app-lost-item *ngSwitchCase="'vintage'" [item]="currentItem"></app-lost-item>
<app-best-item *ngSwitchCase="'bright'" [item]="currentItem"></app-best-item>
<!-- #enddocregion NgSwitch -->
<!-- #docregion NgSwitch-div -->
<div *ngSwitchCase="'bright'">Are you as bright as {{ currentItem.name }}?</div>
<!-- #enddocregion NgSwitch-div -->
<!-- #docregion NgSwitch -->
<app-unknown-item *ngSwitchDefault [item]="currentItem"></app-unknown-item>
</div>
<!-- #enddocregion NgSwitch -->Using NgClass with a method
In the following example, setCurrentClasses() sets the property currentClasses with an object that adds or removes three classes based on the true or false state of three other component properties.
- To use
NgClasswith a method, add the method to the component class.
Each key of the object is a CSS class name. If a key is true, ngClass adds the class. If a key is false, ngClass removes the class.
import {Component, OnInit} from '@angular/core';
import {JsonPipe, NgClass, NgStyle} from '@angular/common';
// #docregion import-ng-if
import {NgIf} from '@angular/common';
// #enddocregion import-ng-if
// #docregion import-ng-for
import {NgFor} from '@angular/common';
// #enddocregion import-ng-for
// #docregion import-ng-switch
import {NgSwitch, NgSwitchCase, NgSwitchDefault} from '@angular/common';
// #enddocregion import-ng-switch
// #docregion import-forms-module
import {FormsModule} from '@angular/forms';
// #enddocregion import-forms-module
import {Item} from './item';
import {ItemDetailComponent} from './item-detail/item-detail.component';
import {ItemSwitchComponents} from './item-switch.component';
import {StoutItemComponent} from './item-switch.component';
// #docregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
@Component({
// #enddocregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
imports: [
NgClass,
NgStyle,
// #docregion import-ng-if
NgIf, // <-- import into the component
// #enddocregion import-ng-if
// #docregion import-ng-for
NgFor, // <-- import into the component
// #enddocregion import-ng-for
// #docregion import-ng-switch
NgSwitch, // <-- import into the component
NgSwitchCase,
NgSwitchDefault,
// #enddocregion import-ng-switch
// #docregion import-forms-module
FormsModule, // <--- import into the component
// #enddocregion import-forms-module
JsonPipe,
ItemDetailComponent,
ItemSwitchComponents,
StoutItemComponent,
// #docregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
],
})
export class AppComponent implements OnInit {
// #enddocregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
canSave = true;
isSpecial = true;
isUnchanged = true;
isActive = true;
nullCustomer: string | null = null;
currentCustomer = {
name: 'Laura',
};
item!: Item; // defined to demonstrate template context precedence
items: Item[] = [];
// #docregion item
currentItem!: Item;
// #enddocregion item
// trackBy change counting
itemsNoTrackByCount = 0;
itemsWithTrackByCount = 0;
itemsWithTrackByCountReset = 0;
itemIdIncrement = 1;
// #docregion setClasses
currentClasses: Record<string, boolean> = {};
// #enddocregion setClasses
// #docregion setStyles
currentStyles: Record<string, string> = {};
// #enddocregion setStyles
ngOnInit() {
this.resetItems();
this.setCurrentClasses();
this.setCurrentStyles();
this.itemsNoTrackByCount = 0;
}
setUppercaseName(name: string) {
this.currentItem.name = name.toUpperCase();
}
// #docregion setClasses
setCurrentClasses() {
// CSS classes: added/removed per current state of component properties
this.currentClasses = {
saveable: this.canSave,
modified: !this.isUnchanged,
special: this.isSpecial,
};
}
// #enddocregion setClasses
// #docregion setStyles
setCurrentStyles() {
// CSS styles: set per current state of component properties
this.currentStyles = {
'font-style': this.canSave ? 'italic' : 'normal',
'font-weight': !this.isUnchanged ? 'bold' : 'normal',
'font-size': this.isSpecial ? '24px' : '12px',
};
}
// #enddocregion setStyles
isActiveToggle() {
this.isActive = !this.isActive;
}
giveNullCustomerValue() {
this.nullCustomer = 'Kelly';
}
resetItems() {
this.items = Item.items.map((item) => item.clone());
this.currentItem = this.items[0];
this.item = this.currentItem;
}
resetList() {
this.resetItems();
this.itemsWithTrackByCountReset = 0;
this.itemsNoTrackByCount = ++this.itemsNoTrackByCount;
}
changeIds() {
this.items.forEach((i) => (i.id += 1 * this.itemIdIncrement));
this.itemsWithTrackByCountReset = -1;
this.itemsNoTrackByCount = ++this.itemsNoTrackByCount;
this.itemsWithTrackByCount = ++this.itemsWithTrackByCount;
}
clearTrackByCounts() {
this.resetItems();
this.itemsNoTrackByCount = 0;
this.itemsWithTrackByCount = 0;
this.itemIdIncrement = 1;
}
// #docregion trackByItems
trackByItems(index: number, item: Item): number {
return item.id;
}
// #enddocregion trackByItems
trackById(index: number, item: any): number {
return item.id;
}
getValue(event: Event): string {
return (event.target as HTMLInputElement).value;
}
// #docregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
}
// #enddocregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module- In the template, add the
ngClassproperty binding tocurrentClassesto set the element's classes:
<h1>Built-in Directives</h1>
<h2>Built-in attribute directives</h2>
<h3 id="ngModel">NgModel (two-way) Binding</h3>
<fieldset>
<h4>NgModel examples</h4>
<p>Current item name: {{ currentItem.name }}</p>
<p>
<label for="without">without NgModel:</label>
<input [value]="currentItem.name" (input)="currentItem.name = getValue($event)" id="without" />
</p>
<p>
<!-- #docregion NgModel-1 -->
<label for="example-ngModel">[(ngModel)]:</label>
<input [(ngModel)]="currentItem.name" id="example-ngModel" />
<!-- #enddocregion NgModel-1 -->
</p>
<p>
<label for="example-change">(ngModelChange)="...name=$event":</label>
<input
[ngModel]="currentItem.name"
(ngModelChange)="currentItem.name = $event"
id="example-change"
/>
</p>
<p>
<label for="example-uppercase"
>(ngModelChange)="setUppercaseName($event)"
<!-- #docregion uppercase -->
<input
[ngModel]="currentItem.name"
(ngModelChange)="setUppercaseName($event)"
id="example-uppercase"
/>
<!-- #enddocregion uppercase -->
</label>
</p>
</fieldset>
<hr />
<h2 id="ngClass">NgClass Binding</h2>
<p>currentClasses is {{ currentClasses | json }}</p>
<!-- #docregion NgClass-1 -->
<div [ngClass]="currentClasses">This div is initially saveable, unchanged, and special.</div>
<!-- #enddocregion NgClass-1 -->
<ul>
<li>
<label for="saveable">saveable</label>
<input type="checkbox" [(ngModel)]="canSave" id="saveable" />
</li>
<li>
<label for="modified">modified:</label>
<input
type="checkbox"
[value]="!isUnchanged"
(change)="isUnchanged = !isUnchanged"
id="modified"
/>
</li>
<li>
<label for="special"
>special: <input type="checkbox" [(ngModel)]="isSpecial" id="special"
/></label>
</li>
</ul>
<button type="button" (click)="setCurrentClasses()">Refresh currentClasses</button>
<div [ngClass]="currentClasses">
This div should be {{ canSave ? '' : 'not' }} saveable,
{{ isUnchanged ? 'unchanged' : 'modified' }} and {{ isSpecial ? '' : 'not' }} special after
clicking "Refresh".
</div>
<br /><br />
<!-- #docregion special-div -->
<!-- toggle the "special" class on/off with a property -->
<div [ngClass]="isSpecial ? 'special' : ''">This div is special</div>
<!-- #enddocregion special-div -->
<div class="helpful study course">Helpful study course</div>
<div [ngClass]="{'helpful': false, 'study': true, 'course': true}">Study course</div>
<!-- NgStyle binding -->
<hr />
<h3>NgStyle Binding</h3>
<div [style.font-size]="isSpecial ? 'x-large' : 'smaller'">This div is x-large or smaller.</div>
<h4>[ngStyle] binding to currentStyles - CSS property names</h4>
<p>currentStyles is {{ currentStyles | json }}</p>
<!-- #docregion NgStyle-2 -->
<div [ngStyle]="currentStyles">
This div is initially italic, normal weight, and extra large (24px).
</div>
<!-- #enddocregion NgStyle-2 -->
<br />
<label for="canSave">italic: <input id="canSave" type="checkbox" [(ngModel)]="canSave" /></label> |
<label for="isUnchanged"
>normal: <input id="isUnchanged" type="checkbox" [(ngModel)]="isUnchanged"
/></label>
|
<label for="isSpecial"
>xlarge: <input id="isSpecial" type="checkbox" [(ngModel)]="isSpecial"
/></label>
<button type="button" (click)="setCurrentStyles()">Refresh currentStyles</button>
<br /><br />
<div [ngStyle]="currentStyles">
This div should be {{ canSave ? 'italic' : 'plain' }},
{{ isUnchanged ? 'normal weight' : 'bold' }} and,
{{ isSpecial ? 'extra large' : 'normal size' }} after clicking "Refresh".
</div>
<hr />
<h2>Built-in structural directives</h2>
<h3 id="ngIf">NgIf Binding</h3>
<div>
<p>If isActive is true, app-item-detail will render:</p>
<!-- #docregion NgIf-1 -->
<app-item-detail *ngIf="isActive" [item]="item"></app-item-detail>
<!-- #enddocregion NgIf-1 -->
<button type="button" (click)="isActiveToggle()">Toggle app-item-detail</button>
</div>
<p>If currentCustomer isn't null, say hello to Laura:</p>
<!-- #docregion NgIf-2 -->
<div *ngIf="currentCustomer">Hello, {{ currentCustomer.name }}</div>
<!-- #enddocregion NgIf-2 -->
<p>nullCustomer is null by default. NgIf guards against null. Give it a value to show it:</p>
<!-- #docregion NgIf-2b -->
<div *ngIf="nullCustomer">
Hello, <span>{{ nullCustomer }}</span>
</div>
<!-- #enddocregion NgIf-2b -->
<button type="button" (click)="giveNullCustomerValue()">Give nullCustomer a value</button>
<h4>NgIf binding with template (no *)</h4>
<ng-template [ngIf]="currentItem">Add {{ currentItem.name }} with template</ng-template>
<hr />
<h4>Show/hide vs. NgIf</h4>
<!-- isSpecial is true -->
<div [class.hidden]="!isSpecial">Show with class</div>
<div [class.hidden]="isSpecial">Hide with class</div>
<p>ItemDetail is in the DOM but hidden</p>
<app-item-detail [class.hidden]="isSpecial"></app-item-detail>
<div [style.display]="isSpecial ? 'block' : 'none'">Show with style</div>
<div [style.display]="isSpecial ? 'none' : 'block'">Hide with style</div>
<hr />
<h2 id="ngFor">NgFor Binding</h2>
<div class="box">
<!-- #docregion NgFor-1, NgFor-1-2 -->
<div *ngFor="let item of items">{{ item.name }}</div>
<!-- #enddocregion NgFor-1, NgFor-1-2 -->
</div>
<p>*ngFor with ItemDetailComponent element</p>
<div class="box">
<!-- #docregion NgFor-2, NgFor-1-2 -->
<app-item-detail *ngFor="let item of items" [item]="item"></app-item-detail>
<!-- #enddocregion NgFor-2, NgFor-1-2 -->
</div>
<h4 id="ngFor-index">*ngFor with index</h4>
<p>with <em>semi-colon</em> separator</p>
<div class="box">
<!-- #docregion NgFor-3 -->
<div *ngFor="let item of items; let i = index">{{ i + 1 }} - {{ item.name }}</div>
<!-- #enddocregion NgFor-3 -->
</div>
<p>with <em>comma</em> separator</p>
<div class="box">
<div *ngFor="let item of items; let i = index">{{ i + 1 }} - {{ item.name }}</div>
</div>
<h4 id="ngFor-trackBy">*ngFor trackBy</h4>
<button type="button" (click)="resetList()">Reset items</button>
<button type="button" (click)="changeIds()">Change ids</button>
<button type="button" (click)="clearTrackByCounts()">Clear counts</button>
<p><em>without</em> trackBy</p>
<div class="box">
<div #noTrackBy *ngFor="let item of items">({{ item.id }}) {{ item.name }}</div>
<div id="noTrackByCnt" *ngIf="itemsNoTrackByCount">
Item DOM elements change #{{ itemsNoTrackByCount }} without trackBy
</div>
</div>
<p>with trackBy</p>
<div class="box">
<div #withTrackBy *ngFor="let item of items; trackBy: trackByItems">
({{ item.id }}) {{ item.name }}
</div>
<div id="withTrackByCnt" *ngIf="itemsWithTrackByCount">
Item DOM elements change #{{ itemsWithTrackByCount }} with trackBy
</div>
</div>
<br /><br /><br />
<p>with trackBy and <em>semi-colon</em> separator</p>
<div class="box">
<!-- #docregion trackBy -->
<div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
<!-- #enddocregion trackBy -->
</div>
<p>with trackBy and <em>comma</em> separator</p>
<div class="box">
<div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
</div>
<p>with trackBy and <em>space</em> separator</p>
<div class="box">
<div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
</div>
<p>with <em>generic</em> trackById function</p>
<div class="box">
<div *ngFor="let item of items; trackBy: trackById">({{ item.id }}) {{ item.name }}</div>
</div>
<hr />
<h2>NgSwitch Binding</h2>
<p>Pick your favorite item</p>
<div>
<label for="item-{{ i }}" *ngFor="let i of items">
<div>
<input id="item-{{ i }}" type="radio" name="items" [(ngModel)]="currentItem" [value]="i" />{{
i.name
}}
</div>
</label>
</div>
<!-- #docregion NgSwitch -->
<div [ngSwitch]="currentItem.feature">
<app-stout-item *ngSwitchCase="'stout'" [item]="currentItem"></app-stout-item>
<app-device-item *ngSwitchCase="'slim'" [item]="currentItem"></app-device-item>
<app-lost-item *ngSwitchCase="'vintage'" [item]="currentItem"></app-lost-item>
<app-best-item *ngSwitchCase="'bright'" [item]="currentItem"></app-best-item>
<!-- #enddocregion NgSwitch -->
<!-- #docregion NgSwitch-div -->
<div *ngSwitchCase="'bright'">Are you as bright as {{ currentItem.name }}?</div>
<!-- #enddocregion NgSwitch-div -->
<!-- #docregion NgSwitch -->
<app-unknown-item *ngSwitchDefault [item]="currentItem"></app-unknown-item>
</div>
<!-- #enddocregion NgSwitch -->For this use case, Angular applies the classes on initialization and in case of changes caused by reassigning the currentClasses object. The full example calls setCurrentClasses() initially with ngOnInit() when the user clicks on the Refresh currentClasses button. These steps are not necessary to implement ngClass.
Setting inline styles with NgStyle
Import NgStyle in the component
To use NgStyle, add it to the component's imports list.
import {NgStyle} from '@angular/common';
@Component({
/* ... */
imports: [NgStyle],
})
export class AppComponent {}Use NgStyle to set multiple inline styles simultaneously, based on the state of the component.
- To use
NgStyle, add a method to the component class.
In the following example, setCurrentStyles() sets the property currentStyles with an object that defines three styles, based on the state of three other component properties.
import {Component, OnInit} from '@angular/core';
import {JsonPipe, NgClass, NgStyle} from '@angular/common';
// #docregion import-ng-if
import {NgIf} from '@angular/common';
// #enddocregion import-ng-if
// #docregion import-ng-for
import {NgFor} from '@angular/common';
// #enddocregion import-ng-for
// #docregion import-ng-switch
import {NgSwitch, NgSwitchCase, NgSwitchDefault} from '@angular/common';
// #enddocregion import-ng-switch
// #docregion import-forms-module
import {FormsModule} from '@angular/forms';
// #enddocregion import-forms-module
import {Item} from './item';
import {ItemDetailComponent} from './item-detail/item-detail.component';
import {ItemSwitchComponents} from './item-switch.component';
import {StoutItemComponent} from './item-switch.component';
// #docregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
@Component({
// #enddocregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
imports: [
NgClass,
NgStyle,
// #docregion import-ng-if
NgIf, // <-- import into the component
// #enddocregion import-ng-if
// #docregion import-ng-for
NgFor, // <-- import into the component
// #enddocregion import-ng-for
// #docregion import-ng-switch
NgSwitch, // <-- import into the component
NgSwitchCase,
NgSwitchDefault,
// #enddocregion import-ng-switch
// #docregion import-forms-module
FormsModule, // <--- import into the component
// #enddocregion import-forms-module
JsonPipe,
ItemDetailComponent,
ItemSwitchComponents,
StoutItemComponent,
// #docregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
],
})
export class AppComponent implements OnInit {
// #enddocregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
canSave = true;
isSpecial = true;
isUnchanged = true;
isActive = true;
nullCustomer: string | null = null;
currentCustomer = {
name: 'Laura',
};
item!: Item; // defined to demonstrate template context precedence
items: Item[] = [];
// #docregion item
currentItem!: Item;
// #enddocregion item
// trackBy change counting
itemsNoTrackByCount = 0;
itemsWithTrackByCount = 0;
itemsWithTrackByCountReset = 0;
itemIdIncrement = 1;
// #docregion setClasses
currentClasses: Record<string, boolean> = {};
// #enddocregion setClasses
// #docregion setStyles
currentStyles: Record<string, string> = {};
// #enddocregion setStyles
ngOnInit() {
this.resetItems();
this.setCurrentClasses();
this.setCurrentStyles();
this.itemsNoTrackByCount = 0;
}
setUppercaseName(name: string) {
this.currentItem.name = name.toUpperCase();
}
// #docregion setClasses
setCurrentClasses() {
// CSS classes: added/removed per current state of component properties
this.currentClasses = {
saveable: this.canSave,
modified: !this.isUnchanged,
special: this.isSpecial,
};
}
// #enddocregion setClasses
// #docregion setStyles
setCurrentStyles() {
// CSS styles: set per current state of component properties
this.currentStyles = {
'font-style': this.canSave ? 'italic' : 'normal',
'font-weight': !this.isUnchanged ? 'bold' : 'normal',
'font-size': this.isSpecial ? '24px' : '12px',
};
}
// #enddocregion setStyles
isActiveToggle() {
this.isActive = !this.isActive;
}
giveNullCustomerValue() {
this.nullCustomer = 'Kelly';
}
resetItems() {
this.items = Item.items.map((item) => item.clone());
this.currentItem = this.items[0];
this.item = this.currentItem;
}
resetList() {
this.resetItems();
this.itemsWithTrackByCountReset = 0;
this.itemsNoTrackByCount = ++this.itemsNoTrackByCount;
}
changeIds() {
this.items.forEach((i) => (i.id += 1 * this.itemIdIncrement));
this.itemsWithTrackByCountReset = -1;
this.itemsNoTrackByCount = ++this.itemsNoTrackByCount;
this.itemsWithTrackByCount = ++this.itemsWithTrackByCount;
}
clearTrackByCounts() {
this.resetItems();
this.itemsNoTrackByCount = 0;
this.itemsWithTrackByCount = 0;
this.itemIdIncrement = 1;
}
// #docregion trackByItems
trackByItems(index: number, item: Item): number {
return item.id;
}
// #enddocregion trackByItems
trackById(index: number, item: any): number {
return item.id;
}
getValue(event: Event): string {
return (event.target as HTMLInputElement).value;
}
// #docregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
}
// #enddocregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module- To set the element's styles, add an
ngStyleproperty binding tocurrentStyles.
<h1>Built-in Directives</h1>
<h2>Built-in attribute directives</h2>
<h3 id="ngModel">NgModel (two-way) Binding</h3>
<fieldset>
<h4>NgModel examples</h4>
<p>Current item name: {{ currentItem.name }}</p>
<p>
<label for="without">without NgModel:</label>
<input [value]="currentItem.name" (input)="currentItem.name = getValue($event)" id="without" />
</p>
<p>
<!-- #docregion NgModel-1 -->
<label for="example-ngModel">[(ngModel)]:</label>
<input [(ngModel)]="currentItem.name" id="example-ngModel" />
<!-- #enddocregion NgModel-1 -->
</p>
<p>
<label for="example-change">(ngModelChange)="...name=$event":</label>
<input
[ngModel]="currentItem.name"
(ngModelChange)="currentItem.name = $event"
id="example-change"
/>
</p>
<p>
<label for="example-uppercase"
>(ngModelChange)="setUppercaseName($event)"
<!-- #docregion uppercase -->
<input
[ngModel]="currentItem.name"
(ngModelChange)="setUppercaseName($event)"
id="example-uppercase"
/>
<!-- #enddocregion uppercase -->
</label>
</p>
</fieldset>
<hr />
<h2 id="ngClass">NgClass Binding</h2>
<p>currentClasses is {{ currentClasses | json }}</p>
<!-- #docregion NgClass-1 -->
<div [ngClass]="currentClasses">This div is initially saveable, unchanged, and special.</div>
<!-- #enddocregion NgClass-1 -->
<ul>
<li>
<label for="saveable">saveable</label>
<input type="checkbox" [(ngModel)]="canSave" id="saveable" />
</li>
<li>
<label for="modified">modified:</label>
<input
type="checkbox"
[value]="!isUnchanged"
(change)="isUnchanged = !isUnchanged"
id="modified"
/>
</li>
<li>
<label for="special"
>special: <input type="checkbox" [(ngModel)]="isSpecial" id="special"
/></label>
</li>
</ul>
<button type="button" (click)="setCurrentClasses()">Refresh currentClasses</button>
<div [ngClass]="currentClasses">
This div should be {{ canSave ? '' : 'not' }} saveable,
{{ isUnchanged ? 'unchanged' : 'modified' }} and {{ isSpecial ? '' : 'not' }} special after
clicking "Refresh".
</div>
<br /><br />
<!-- #docregion special-div -->
<!-- toggle the "special" class on/off with a property -->
<div [ngClass]="isSpecial ? 'special' : ''">This div is special</div>
<!-- #enddocregion special-div -->
<div class="helpful study course">Helpful study course</div>
<div [ngClass]="{'helpful': false, 'study': true, 'course': true}">Study course</div>
<!-- NgStyle binding -->
<hr />
<h3>NgStyle Binding</h3>
<div [style.font-size]="isSpecial ? 'x-large' : 'smaller'">This div is x-large or smaller.</div>
<h4>[ngStyle] binding to currentStyles - CSS property names</h4>
<p>currentStyles is {{ currentStyles | json }}</p>
<!-- #docregion NgStyle-2 -->
<div [ngStyle]="currentStyles">
This div is initially italic, normal weight, and extra large (24px).
</div>
<!-- #enddocregion NgStyle-2 -->
<br />
<label for="canSave">italic: <input id="canSave" type="checkbox" [(ngModel)]="canSave" /></label> |
<label for="isUnchanged"
>normal: <input id="isUnchanged" type="checkbox" [(ngModel)]="isUnchanged"
/></label>
|
<label for="isSpecial"
>xlarge: <input id="isSpecial" type="checkbox" [(ngModel)]="isSpecial"
/></label>
<button type="button" (click)="setCurrentStyles()">Refresh currentStyles</button>
<br /><br />
<div [ngStyle]="currentStyles">
This div should be {{ canSave ? 'italic' : 'plain' }},
{{ isUnchanged ? 'normal weight' : 'bold' }} and,
{{ isSpecial ? 'extra large' : 'normal size' }} after clicking "Refresh".
</div>
<hr />
<h2>Built-in structural directives</h2>
<h3 id="ngIf">NgIf Binding</h3>
<div>
<p>If isActive is true, app-item-detail will render:</p>
<!-- #docregion NgIf-1 -->
<app-item-detail *ngIf="isActive" [item]="item"></app-item-detail>
<!-- #enddocregion NgIf-1 -->
<button type="button" (click)="isActiveToggle()">Toggle app-item-detail</button>
</div>
<p>If currentCustomer isn't null, say hello to Laura:</p>
<!-- #docregion NgIf-2 -->
<div *ngIf="currentCustomer">Hello, {{ currentCustomer.name }}</div>
<!-- #enddocregion NgIf-2 -->
<p>nullCustomer is null by default. NgIf guards against null. Give it a value to show it:</p>
<!-- #docregion NgIf-2b -->
<div *ngIf="nullCustomer">
Hello, <span>{{ nullCustomer }}</span>
</div>
<!-- #enddocregion NgIf-2b -->
<button type="button" (click)="giveNullCustomerValue()">Give nullCustomer a value</button>
<h4>NgIf binding with template (no *)</h4>
<ng-template [ngIf]="currentItem">Add {{ currentItem.name }} with template</ng-template>
<hr />
<h4>Show/hide vs. NgIf</h4>
<!-- isSpecial is true -->
<div [class.hidden]="!isSpecial">Show with class</div>
<div [class.hidden]="isSpecial">Hide with class</div>
<p>ItemDetail is in the DOM but hidden</p>
<app-item-detail [class.hidden]="isSpecial"></app-item-detail>
<div [style.display]="isSpecial ? 'block' : 'none'">Show with style</div>
<div [style.display]="isSpecial ? 'none' : 'block'">Hide with style</div>
<hr />
<h2 id="ngFor">NgFor Binding</h2>
<div class="box">
<!-- #docregion NgFor-1, NgFor-1-2 -->
<div *ngFor="let item of items">{{ item.name }}</div>
<!-- #enddocregion NgFor-1, NgFor-1-2 -->
</div>
<p>*ngFor with ItemDetailComponent element</p>
<div class="box">
<!-- #docregion NgFor-2, NgFor-1-2 -->
<app-item-detail *ngFor="let item of items" [item]="item"></app-item-detail>
<!-- #enddocregion NgFor-2, NgFor-1-2 -->
</div>
<h4 id="ngFor-index">*ngFor with index</h4>
<p>with <em>semi-colon</em> separator</p>
<div class="box">
<!-- #docregion NgFor-3 -->
<div *ngFor="let item of items; let i = index">{{ i + 1 }} - {{ item.name }}</div>
<!-- #enddocregion NgFor-3 -->
</div>
<p>with <em>comma</em> separator</p>
<div class="box">
<div *ngFor="let item of items; let i = index">{{ i + 1 }} - {{ item.name }}</div>
</div>
<h4 id="ngFor-trackBy">*ngFor trackBy</h4>
<button type="button" (click)="resetList()">Reset items</button>
<button type="button" (click)="changeIds()">Change ids</button>
<button type="button" (click)="clearTrackByCounts()">Clear counts</button>
<p><em>without</em> trackBy</p>
<div class="box">
<div #noTrackBy *ngFor="let item of items">({{ item.id }}) {{ item.name }}</div>
<div id="noTrackByCnt" *ngIf="itemsNoTrackByCount">
Item DOM elements change #{{ itemsNoTrackByCount }} without trackBy
</div>
</div>
<p>with trackBy</p>
<div class="box">
<div #withTrackBy *ngFor="let item of items; trackBy: trackByItems">
({{ item.id }}) {{ item.name }}
</div>
<div id="withTrackByCnt" *ngIf="itemsWithTrackByCount">
Item DOM elements change #{{ itemsWithTrackByCount }} with trackBy
</div>
</div>
<br /><br /><br />
<p>with trackBy and <em>semi-colon</em> separator</p>
<div class="box">
<!-- #docregion trackBy -->
<div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
<!-- #enddocregion trackBy -->
</div>
<p>with trackBy and <em>comma</em> separator</p>
<div class="box">
<div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
</div>
<p>with trackBy and <em>space</em> separator</p>
<div class="box">
<div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
</div>
<p>with <em>generic</em> trackById function</p>
<div class="box">
<div *ngFor="let item of items; trackBy: trackById">({{ item.id }}) {{ item.name }}</div>
</div>
<hr />
<h2>NgSwitch Binding</h2>
<p>Pick your favorite item</p>
<div>
<label for="item-{{ i }}" *ngFor="let i of items">
<div>
<input id="item-{{ i }}" type="radio" name="items" [(ngModel)]="currentItem" [value]="i" />{{
i.name
}}
</div>
</label>
</div>
<!-- #docregion NgSwitch -->
<div [ngSwitch]="currentItem.feature">
<app-stout-item *ngSwitchCase="'stout'" [item]="currentItem"></app-stout-item>
<app-device-item *ngSwitchCase="'slim'" [item]="currentItem"></app-device-item>
<app-lost-item *ngSwitchCase="'vintage'" [item]="currentItem"></app-lost-item>
<app-best-item *ngSwitchCase="'bright'" [item]="currentItem"></app-best-item>
<!-- #enddocregion NgSwitch -->
<!-- #docregion NgSwitch-div -->
<div *ngSwitchCase="'bright'">Are you as bright as {{ currentItem.name }}?</div>
<!-- #enddocregion NgSwitch-div -->
<!-- #docregion NgSwitch -->
<app-unknown-item *ngSwitchDefault [item]="currentItem"></app-unknown-item>
</div>
<!-- #enddocregion NgSwitch -->For this use case, Angular applies the styles upon initialization and in case of changes. To do this, the full example calls setCurrentStyles() initially with ngOnInit() and when the dependent properties change through a button click. However, these steps are not necessary to implement ngStyle on its own.