Template Syntax
Interpolation
Section titled “Interpolation”<!-- String interpolation --><p>{{ title }}</p><p>{{ user.name }}</p><p>{{ 1 + 1 }}</p><p>{{ getName() }}</p><p>{{ user?.name }}</p> <!-- Safe navigation -->Property Binding
Section titled “Property Binding”<!-- Element property --><img [src]="imageUrl"><button [disabled]="isDisabled">Click</button><input [value]="username">
<!-- Class binding --><div [class.active]="isActive">Text</div><div [class]="'btn btn-primary'">Button</div><div [class]="classes">Dynamic classes</div>
<!-- Style binding --><div [style.color]="textColor">Colored text</div><div [style.font-size.px]="fontSize">Text</div><div [style]="{'color': 'red', 'font-size': '14px'}">Styled</div>
<!-- Attribute binding --><button [attr.aria-label]="label">Button</button><div [attr.data-id]="userId">Data</div>Event Binding
Section titled “Event Binding”<!-- Basic events --><button (click)="onClick()">Click</button><input (input)="onInput($event)"><input (keyup)="onKeyup($event)"><input (keyup.enter)="onEnter()">
<!-- Event with parameter --><button (click)="onDelete(user.id)">Delete</button>
<!-- $event object --><input (input)="onInput($event)">
<!-- Multiple events --><input (focus)="onFocus()" (blur)="onBlur()" (input)="onInput($event)">onInput(event: Event) { const value = (event.target as HTMLInputElement).value; console.log(value);}Two-way Binding
Section titled “Two-way Binding”<!-- Using ngModel (FormsModule) --><input [(ngModel)]="username">
<!-- Equivalent to: --><input [ngModel]="username" (ngModelChange)="username = $event">
<!-- Custom two-way binding --><app-counter [(count)]="counter"></app-counter>// Custom two-way binding in component (signal-based)import { Component, input, output } from '@angular/core';
@Component({ selector: 'app-counter', standalone: true})export class CounterComponent { count = input<number>(0); countChange = output<number>();
increment() { const newCount = this.count() + 1; this.countChange.emit(newCount); }}Template Reference Variables
Section titled “Template Reference Variables”<!-- Element reference --><input #nameInput><button (click)="nameInput.focus()">Focus</button>
<!-- Component reference --><app-child #child></app-child><button (click)="child.doSomething()">Do</button>
<!-- Form reference --><form #userForm="ngForm"> <input name="username" ngModel> <button [disabled]="userForm.invalid">Submit</button></form>
<!-- Directive reference --><div appHighlight #highlight="appHighlight"> <button (click)="highlight.changeColor('red')">Red</button></div>Structural Directives
Section titled “Structural Directives”<!-- *ngIf --><div *ngIf="isVisible">Visible</div><div *ngIf="user; else loading">{{ user.name }}</div><ng-template #loading>Loading...</ng-template>
<!-- *ngIf with as --><div *ngIf="user$ | async as user"> {{ user.name }}</div>
<!-- *ngFor --><li *ngFor="let item of items">{{ item }}</li><li *ngFor="let item of items; index as i"> {{ i }}: {{ item }}</li><li *ngFor="let item of items; trackBy: trackByFn"> {{ item.name }}</li>
<!-- *ngFor variables --><div *ngFor="let item of items; index as i; first as isFirst; last as isLast; even as isEven; odd as isOdd"> {{ i }}: {{ item }}</div>
<!-- *ngSwitch --><div [ngSwitch]="status"> <p *ngSwitchCase="'active'">Active</p> <p *ngSwitchCase="'inactive'">Inactive</p> <p *ngSwitchDefault>Unknown</p></div>ng-template
Section titled “ng-template”<!-- Basic template --><ng-template #template> <p>Template content</p></ng-template>
<!-- Conditional template --><div *ngIf="show; else elseBlock">Main content</div><ng-template #elseBlock> <p>Else content</p></ng-template>
<!-- Template with context --><ng-template #userTemplate let-user let-i="index"> <p>{{ i }}: {{ user.name }}</p></ng-template>
<!-- Use with ngTemplateOutlet --><ng-container *ngTemplateOutlet="userTemplate; context: { $implicit: user, index: 0 }"></ng-container>ng-container
Section titled “ng-container”<!-- Grouping without extra DOM element --><ng-container *ngIf="isVisible"> <h1>Title</h1> <p>Content</p></ng-container>
<!-- Multiple structural directives --><ng-container *ngFor="let item of items"> <div *ngIf="item.active">{{ item.name }}</div></ng-container>ng-content
Section titled “ng-content”<!-- Component with content projection -->@Component({ selector: 'app-card', standalone: true, template: ` <div class="card"> <ng-content></ng-content> </div> `})
<!-- Usage --><app-card> <h2>Card Title</h2> <p>Card content</p></app-card>
<!-- Multiple slots -->@Component({ selector: 'app-layout', standalone: true, template: ` <header> <ng-content select="[slot=header]"></ng-content> </header> <main> <ng-content></ng-content> </main> <footer> <ng-content select="[slot=footer]"></ng-content> </footer> `})
<!-- Usage --><app-layout> <div slot="header">Header content</div> <p>Main content</p> <div slot="footer">Footer content</div></app-layout>Pipes in Templates
Section titled “Pipes in Templates”<!-- Basic pipe --><p>{{ name | uppercase }}</p>
<!-- Pipe with parameters --><p>{{ price | currency:'USD':'symbol':'1.2-2' }}</p>
<!-- Chained pipes --><p>{{ date | date:'short' | uppercase }}</p>
<!-- Async pipe --><p>{{ user$ | async }}</p><div *ngIf="users$ | async as users"> <p *ngFor="let user of users">{{ user.name }}</p></div>Safe Navigation Operator
Section titled “Safe Navigation Operator”<!-- Safe navigation (?) --><p>{{ user?.name }}</p><p>{{ user?.address?.city }}</p>
<!-- Without safe navigation (throws error if null) --><p>{{ user.name }}</p> <!-- Error if user is null -->
<!-- Combination with async --><p>{{ (user$ | async)?.name }}</p>Non-null Assertion
Section titled “Non-null Assertion”<!-- Non-null assertion (!) --><p>{{ user!.name }}</p> <!-- Tells TS user is not null -->Template Expressions
Section titled “Template Expressions”<!-- Arithmetic --><p>{{ 1 + 1 }}</p><p>{{ price * quantity }}</p>
<!-- Comparison --><p>{{ count > 10 }}</p><p>{{ status === 'active' }}</p>
<!-- Logical --><p>{{ isActive && isVisible }}</p><p>{{ user || 'Guest' }}</p>
<!-- Ternary --><p>{{ isActive ? 'Active' : 'Inactive' }}</p>
<!-- Method calls --><p>{{ getFullName() }}</p><p>{{ user.getName() }}</p>
<!-- Limitations: --><!-- ❌ No assignments: count = 5 --><!-- ❌ No new/typeof/instanceof --><!-- ❌ No chaining: ; --><!-- ❌ No increment/decrement: count++ -->Best Practices
Section titled “Best Practices”- Keep template expressions simple
- Use pipes for transformations
- Use trackBy with *ngFor
- Use async pipe for observables
- Use safe navigation for nullable values
- Avoid complex logic in templates (move to component)
- Use ng-container to avoid extra DOM elements
- Use ng-template for reusable templates

