Angular Common provides essential directives for DOM manipulation, conditional rendering, and iteration that form the core of Angular's declarative template syntax.
Conditionally includes or excludes a template based on an expression evaluation.
/**
* Conditionally includes a template based on the value of an expression
* Supports then/else template references for complex conditional rendering
*/
export class NgIf<T = unknown> {
/** The condition expression that determines whether to show the template */
ngIf: T | null | undefined;
/** Template to show when condition is truthy */
ngIfThen: TemplateRef<NgIfContext<T>> | null;
/** Template to show when condition is falsy */
ngIfElse: TemplateRef<NgIfContext<T>> | null;
/** Type guard for template context */
static ngTemplateContextGuard<T>(dir: NgIf<T>, ctx: any): ctx is NgIfContext<Exclude<T, false | 0 | '' | null | undefined>>;
}
/** Context available in NgIf template */
export interface NgIfContext<T = unknown> {
/** Implicit context variable containing the expression value */
$implicit: T;
/** Explicit reference to the expression value */
ngIf: T;
}Usage Examples:
// Basic conditional rendering
@Component({
template: `
<div *ngIf="isLoggedIn">Welcome back!</div>
<div *ngIf="!isLoggedIn">Please log in</div>
`
})
export class LoginComponent {
isLoggedIn = false;
}
// With then/else templates
@Component({
template: `
<div *ngIf="user; then userProfile; else loginPrompt"></div>
<ng-template #userProfile>
<h2>{{ user.name }}</h2>
</ng-template>
<ng-template #loginPrompt>
<button (click)="login()">Login</button>
</ng-template>
`
})
export class ProfileComponent {
user: User | null = null;
}
// Type-safe usage with context
@Component({
template: `
<div *ngIf="user as currentUser">
Hello {{ currentUser.name }}! <!-- TypeScript knows currentUser is not null -->
</div>
`
})
export class TypeSafeComponent {
user: User | null = null;
}Repeats a template for each item in a collection with full type safety and change tracking.
/**
* Repeats a template for each item in an iterable collection
* Provides context variables for index, count, and position information
*/
export class NgForOf<T, U extends NgIterable<T> = NgIterable<T>> implements DoCheck {
/** The collection to iterate over */
ngForOf: U | null | undefined;
/** Function to track items for efficient updates */
ngForTrackBy: TrackByFunction<T> | null;
/** Template to repeat for each item */
ngForTemplate: TemplateRef<NgForOfContext<T, U>>;
/** Type guard for template context */
static ngTemplateContextGuard<T, U extends NgIterable<T>>(
dir: NgForOf<T, U>,
ctx: any
): ctx is NgForOfContext<T, U>;
ngDoCheck(): void;
}
/** Context available in NgFor template */
export interface NgForOfContext<T, U extends NgIterable<T> = NgIterable<T>> {
/** Current item from the collection */
$implicit: T;
/** Reference to the collection being iterated */
ngForOf: U;
/** Zero-based index of current item */
index: number;
/** Total number of items in collection */
count: number;
/** True if this is the first item */
readonly first: boolean;
/** True if this is the last item */
readonly last: boolean;
/** True if index is even */
readonly even: boolean;
/** True if index is odd */
readonly odd: boolean;
}
/** Type alias for backwards compatibility */
export const NgFor = NgForOf;
/** Function type for tracking items in collections */
export type TrackByFunction<T> = (index: number, item: T) => any;Usage Examples:
// Basic list rendering
@Component({
template: `
<ul>
<li *ngFor="let item of items">{{ item.name }}</li>
</ul>
`
})
export class ListComponent {
items = [
{ name: 'Item 1' },
{ name: 'Item 2' },
{ name: 'Item 3' }
];
}
// With index and position variables
@Component({
template: `
<div *ngFor="let item of items; let i = index; let first = first; let last = last">
<span [class.first]="first" [class.last]="last">
{{ i + 1 }}. {{ item.name }}
</span>
</div>
`
})
export class IndexedListComponent {
items = [{ name: 'A' }, { name: 'B' }, { name: 'C' }];
}
// With trackBy for performance
@Component({
template: `
<div *ngFor="let item of items; trackBy: trackById">
{{ item.name }}
</div>
`
})
export class TrackedListComponent {
items = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' }
];
trackById(index: number, item: any): number {
return item.id;
}
}Conditionally swaps the contents of templates based on a switch expression.
/**
* Container directive that switches between child templates based on expression value
* Works with NgSwitchCase and NgSwitchDefault directives
*/
export class NgSwitch {
/** Expression to match against case values */
ngSwitch: any;
}
/**
* Template that displays when its value matches the NgSwitch expression
*/
export class NgSwitchCase implements DoCheck {
/** Value to match against NgSwitch expression */
ngSwitchCase: any;
ngDoCheck(): void;
}
/**
* Template that displays when no NgSwitchCase matches
*/
export class NgSwitchDefault {
}Usage Examples:
@Component({
template: `
<div [ngSwitch]="userRole">
<div *ngSwitchCase="'admin'">Admin Panel</div>
<div *ngSwitchCase="'user'">User Dashboard</div>
<div *ngSwitchCase="'guest'">Guest View</div>
<div *ngSwitchDefault>Unknown Role</div>
</div>
`
})
export class RoleBasedComponent {
userRole: 'admin' | 'user' | 'guest' | 'unknown' = 'user';
}
// Complex switch with multiple cases
@Component({
template: `
<div [ngSwitch]="status">
<div *ngSwitchCase="'loading'">
<span class="spinner"></span> Loading...
</div>
<div *ngSwitchCase="'success'">
<span class="check"></span> Success!
</div>
<div *ngSwitchCase="'error'">
<span class="error"></span> Error occurred
</div>
<div *ngSwitchDefault>
Ready
</div>
</div>
`
})
export class StatusComponent {
status: 'loading' | 'success' | 'error' | 'ready' = 'ready';
}Conditionally displays templates based on plural categories for internationalization.
/**
* Switches templates based on plural category (zero, one, two, few, many, other)
* Used for internationalization of content that varies by count
*/
export class NgPlural {
/** Number value to determine plural category */
ngPlural: number;
/** Add case mapping for plural category */
addCase(value: string, switchView: SwitchView): void;
}
/**
* Template case for specific plural category
*/
export class NgPluralCase {
/** Plural category value (zero, one, two, few, many, other) */
value: string;
}Usage Examples:
@Component({
template: `
<div [ngPlural]="messageCount">
<ng-template ngPluralCase="=0">No messages</ng-template>
<ng-template ngPluralCase="=1">One message</ng-template>
<ng-template ngPluralCase="other">{{ messageCount }} messages</ng-template>
</div>
`
})
export class MessageCountComponent {
messageCount = 5;
}Conditionally applies CSS classes to elements based on expressions.
/**
* Conditionally applies CSS classes to an element
* Supports arrays, objects, and strings for flexible class assignment
*/
export class NgClass implements DoCheck {
/** Static CSS class string */
klass: string;
/** Dynamic class expression */
ngClass: NgClassSupportedTypes;
ngDoCheck(): void;
}
/** Supported input types for NgClass */
export type NgClassSupportedTypes = string[] | Set<string> | { [klass: string]: any } | null | undefined;Usage Examples:
@Component({
template: `
<!-- Object syntax -->
<div [ngClass]="{
'active': isActive,
'disabled': isDisabled,
'highlight': needsHighlight
}">
Dynamic classes via object
</div>
<!-- Array syntax -->
<div [ngClass]="['btn', 'btn-primary', isLarge ? 'btn-lg' : 'btn-sm']">
Dynamic classes via array
</div>
<!-- String syntax -->
<div [ngClass]="getClassNames()">
Dynamic classes via string
</div>
<!-- Combined with static classes -->
<div class="base-class" [ngClass]="conditionalClasses">
Static + dynamic classes
</div>
`
})
export class DynamicClassComponent {
isActive = true;
isDisabled = false;
needsHighlight = true;
isLarge = false;
conditionalClasses = {
'success': true,
'animated': false
};
getClassNames(): string {
return this.isActive ? 'active-state success' : 'inactive-state';
}
}Conditionally applies inline styles to elements.
/**
* Conditionally applies inline styles to an element
* Accepts an object mapping style properties to values
*/
export class NgStyle implements DoCheck {
/** Style object mapping properties to values */
ngStyle: { [klass: string]: any } | null | undefined;
ngDoCheck(): void;
}Usage Examples:
@Component({
template: `
<!-- Object syntax with conditional values -->
<div [ngStyle]="{
'color': textColor,
'font-size': fontSize + 'px',
'display': isVisible ? 'block' : 'none',
'background-color': isHighlighted ? '#ffff00' : 'transparent'
}">
Dynamic inline styles
</div>
<!-- Computed styles -->
<div [ngStyle]="getStyles()">
Computed dynamic styles
</div>
`
})
export class DynamicStyleComponent {
textColor = '#333';
fontSize = 16;
isVisible = true;
isHighlighted = false;
getStyles(): { [key: string]: any } {
return {
'width': this.isExpanded ? '300px' : '200px',
'height': this.height + 'px',
'border': this.hasBorder ? '1px solid #ccc' : 'none'
};
}
isExpanded = false;
height = 100;
hasBorder = true;
}Inserts an embedded view from a TemplateRef with optional context.
/**
* Inserts an embedded view from a TemplateRef into the DOM
* Supports passing context data to the template
*/
export class NgTemplateOutlet<C = unknown> implements OnChanges {
/** Template context data */
ngTemplateOutletContext: C | null;
/** Template reference to render */
ngTemplateOutlet: TemplateRef<C> | null;
/** Custom injector for the template */
ngTemplateOutletInjector: Injector | null;
ngOnChanges(changes: SimpleChanges): void;
}Usage Examples:
@Component({
template: `
<!-- Basic template outlet -->
<ng-container *ngTemplateOutlet="selectedTemplate"></ng-container>
<!-- With context -->
<ng-container *ngTemplateOutlet="itemTemplate; context: {
$implicit: currentItem,
index: currentIndex
}"></ng-container>
<!-- Dynamic template selection -->
<ng-container *ngTemplateOutlet="getTemplate()"></ng-container>
<!-- Template definitions -->
<ng-template #userTemplate let-user>
<div>User: {{ user.name }}</div>
</ng-template>
<ng-template #adminTemplate let-user>
<div>Admin: {{ user.name }} ({{ user.role }})</div>
</ng-template>
<ng-template #itemTemplate let-item let-i="index">
<div>{{ i }}: {{ item.name }}</div>
</ng-template>
`
})
export class TemplateOutletComponent {
@ViewChild('userTemplate') userTemplate!: TemplateRef<any>;
@ViewChild('adminTemplate') adminTemplate!: TemplateRef<any>;
currentItem = { name: 'Item 1' };
currentIndex = 0;
selectedTemplate: TemplateRef<any> | null = null;
ngAfterViewInit() {
this.selectedTemplate = this.userTemplate;
}
getTemplate(): TemplateRef<any> | null {
return this.isAdmin ? this.adminTemplate : this.userTemplate;
}
isAdmin = false;
}Instantiates a component and inserts its view into the DOM.
/**
* Instantiates a component dynamically and inserts its view into the DOM
* Supports passing inputs, custom injector, and content projection
*/
export class NgComponentOutlet implements OnChanges, DoCheck, OnDestroy {
/** Component type to instantiate */
ngComponentOutlet: Type<any> | null;
/** Input properties to pass to component */
ngComponentOutletInputs?: Record<string, unknown>;
/** Custom injector for the component */
ngComponentOutletInjector?: Injector;
/** Projected content as arrays of DOM nodes */
ngComponentOutletContent?: any[][];
/** NgModule to provide dependencies */
ngComponentOutletNgModule?: Type<any>;
/** @deprecated NgModule factory */
ngComponentOutletNgModuleFactory?: NgModuleFactory<any>;
ngOnChanges(changes: SimpleChanges): void;
ngDoCheck(): void;
ngOnDestroy(): void;
}Usage Examples:
@Component({
selector: 'user-card',
template: '<div>{{ name }} - {{ role }}</div>'
})
export class UserCardComponent {
@Input() name!: string;
@Input() role!: string;
}
@Component({
selector: 'admin-panel',
template: '<div>Admin Panel</div>'
})
export class AdminPanelComponent {}
@Component({
template: `
<!-- Basic component outlet -->
<ng-container *ngComponentOutlet="selectedComponent"></ng-container>
<!-- With inputs -->
<ng-container *ngComponentOutlet="UserCardComponent; inputs: userInputs"></ng-container>
<!-- With custom injector -->
<ng-container *ngComponentOutlet="selectedComponent; injector: customInjector"></ng-container>
`
})
export class DynamicComponentComponent {
UserCardComponent = UserCardComponent;
selectedComponent: Type<any> = UserCardComponent;
userInputs = {
name: 'John Doe',
role: 'Developer'
};
customInjector = Injector.create({
providers: [
{ provide: 'CONFIG', useValue: { theme: 'dark' } }
]
});
switchToAdmin() {
this.selectedComponent = AdminPanelComponent;
}
}// Context interfaces
export interface NgIfContext<T = unknown> {
$implicit: T;
ngIf: T;
}
export interface NgForOfContext<T, U extends NgIterable<T> = NgIterable<T>> {
$implicit: T;
ngForOf: U;
index: number;
count: number;
readonly first: boolean;
readonly last: boolean;
readonly even: boolean;
readonly odd: boolean;
}
// Type definitions
export type NgClassSupportedTypes = string[] | Set<string> | { [klass: string]: any } | null | undefined;
export type NgIterable<T> = Array<T> | Iterable<T>;
export type TrackByFunction<T> = (index: number, item: T) => any;
// Common directives collection
export const COMMON_DIRECTIVES: Provider[] = [
NgClass,
NgComponentOutlet,
NgForOf,
NgIf,
NgTemplateOutlet,
NgStyle,
NgSwitch,
NgSwitchCase,
NgSwitchDefault,
NgPlural,
NgPluralCase,
];