or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

directives.mdhttp.mdi18n.mdindex.mdlocation.mdpipes.mdplatform.mdtesting.md
tile.json

directives.mddocs/

Template Directives

Angular Common provides essential directives for DOM manipulation, conditional rendering, and iteration that form the core of Angular's declarative template syntax.

Capabilities

Structural Directives

NgIf - Conditional Rendering

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;
}

NgForOf (NgFor) - List Rendering

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;
  }
}

NgSwitch - Multi-way Conditional Rendering

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';
}

NgPlural - Pluralization

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;
}

Attribute Directives

NgClass - Dynamic CSS Classes

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';
  }
}

NgStyle - Dynamic Inline Styles

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;
}

Component Directives

NgTemplateOutlet - Dynamic Template Rendering

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;
}

NgComponentOutlet - Dynamic Component Rendering

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;
  }
}

Types and Interfaces

// 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,
];