AngularJSAngular Cheat Sheet

Angular Cheat Sheet

A quick-reference guide to the most frequently used Angular syntax, decorators, and patterns. Bookmark this page for fast lookups while you code.

Component Anatomy

TS
import { Component, Input, Output, EventEmitter, OnInit, inject,
         ChangeDetectionStrategy, signal } from '@angular/core';

@Component({
  standalone: true,                          // No NgModule needed
  selector: 'app-example',                  // HTML tag: <app-example />
  templateUrl: './example.component.html',  // Or: template: `...`
  styleUrl: './example.component.scss',     // Or: styles: [`...`]
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [OtherComponent, SomePipe],      // Import what this component uses
})
export class ExampleComponent implements OnInit {
  // Inputs
  @Input({ required: true }) title!: string;
  @Input({ alias: 'size' }) buttonSize: 'sm' | 'lg' = 'sm';

  // Outputs
  @Output() clicked = new EventEmitter<string>();

  // Signals
  count = signal(0);

  // Dependency injection
  private router = inject(Router);

  ngOnInit() { /* runs once after component creation */ }

  onClick() {
    this.clicked.emit('clicked!');
    this.count.update((n) => n + 1);
  }
}
Lifecycle Hooks

Hook

When It Runs

ngOnChanges(changes)

When input properties change (before ngOnInit on first run)

ngOnInit()

Once after the first ngOnChanges

ngDoCheck()

On every change detection run (expensive — use sparingly)

ngAfterContentInit()

After ng-content is projected into the component

ngAfterContentChecked()

After projected content is checked

ngAfterViewInit()

After the component view and child views are initialized

ngAfterViewChecked()

After the component view is checked

ngOnDestroy()

Just before Angular destroys the component

Template Syntax

HTML
<!-- Interpolation -->
<p>{{ expression }}</p>
<p>{{ user?.name ?? 'Guest' }}</p>

<!-- Property binding -->
<input [value]="name" />
<div [class.active]="isActive" />
<button [disabled]="isLoading" />

<!-- Event binding -->
<button (click)="onClick()">Click</button>
<input (keyup.enter)="onEnter()" />
<form (ngSubmit)="onSubmit()" />

<!-- Two-way binding -->
<input [(ngModel)]="username" />

<!-- Attribute binding -->
<td [attr.colspan]="colSpan">...</td>

<!-- Template reference variable -->
<input #myInput />
<button (click)="console.log(myInput.value)">Log</button>

<!-- Pipe -->
<p>{{ price | currency:'USD' }}</p>
<p>{{ name | uppercase | trim }}</p>
Control Flow (@if, @for, @switch)

HTML
<!-- @if / @else if / @else -->
@if (user) {
  <p>Welcome, {{ user.name }}</p>
} @else if (loading) {
  <p>Loading...</p>
} @else {
  <p>Please log in</p>
}

<!-- @for -->
@for (item of items; track item.id) {
  <li>{{ item.name }}</li>
} @empty {
  <li>No items found</li>
}

<!-- @switch -->
@switch (status) {
  @case ('active') { <span class="green">Active</span> }
  @case ('inactive') { <span class="red">Inactive</span> }
  @default { <span>Unknown</span> }
}

<!-- @defer -->
@defer (on viewport) {
  <app-heavy-component />
} @placeholder {
  <div>Coming soon...</div>
} @loading { <app-spinner /> }
Signals

TS
import { signal, computed, effect, toSignal, toObservable } from '@angular/core';

// Create a signal
const count = signal(0);

// Read — always call it as a function
console.log(count()); // 0

// Update
count.set(5);                          // Set to specific value
count.update((n) => n + 1);           // Update based on current value
count.mutate((arr) => arr.push(1));   // Mutate in place (arrays/objects)

// Computed — derived signal, lazy and cached
const doubled = computed(() => count() * 2);

// Effect — side effect when signals change
const cleanup = effect(() => {
  console.log('count is now:', count()); // Runs whenever count changes
});
cleanup.destroy(); // Stop the effect

// Signal ↔ Observable interop
const count$ = toObservable(count);    // Signal → Observable
const inputSig = toSignal(input$, { initialValue: '' }); // Observable → Signal
Directives

TS
// Attribute directive
@Directive({
  standalone: true,
  selector: '[appHighlight]',
  host: {
    '(mouseenter)': 'onEnter()',
    '[style.color]': 'color',
  },
})
export class HighlightDirective {
  @Input() appHighlight = 'yellow';
  color = 'black';

  onEnter() { this.color = this.appHighlight; }
}

// Structural directive — use built-in @if/@for whenever possible
// For custom: inject TemplateRef and ViewContainerRef
Services and Dependency Injection

TS
// Provided in root — singleton, tree-shakeable
@Injectable({ providedIn: 'root' })
export class GlobalService {}

// Provided at component level — new instance per component
@Component({ providers: [LocalService] })
export class MyComponent {}

// Injection tokens
const THEME = new InjectionToken<string>('theme');
providers: [{ provide: THEME, useValue: 'dark' }]
const theme = inject(THEME);

// Factory provider
providers: [{
  provide: LogService,
  useFactory: (http: HttpClient) => new LogService(http, 'production'),
  deps: [HttpClient],
}]
Routing

TS
// Routes definition
export const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'users/:id', component: UserDetailComponent },
  { path: 'admin', loadChildren: () => import('./admin/admin.routes').then(m => m.adminRoutes) },
  { path: '**', redirectTo: '' },
];

// In a component
const router = inject(Router);
const route = inject(ActivatedRoute);

// Read params
const id = route.snapshot.paramMap.get('id');
const id$ = route.paramMap.pipe(map(p => p.get('id')));

// Navigate
router.navigate(['/users', userId]);
router.navigate(['../'], { relativeTo: route });
router.navigateByUrl('/dashboard?tab=overview');
Forms

TS
import { FormGroup, FormControl, FormArray, Validators } from '@angular/forms';

// Reactive form
form = new FormGroup({
  email: new FormControl('', [Validators.required, Validators.email]),
  password: new FormControl('', [Validators.required, Validators.minLength(8)]),
  address: new FormGroup({
    street: new FormControl(''),
    city: new FormControl(''),
  }),
  phones: new FormArray([new FormControl('')]),
});

// Access values and state
form.value                   // { email: '', password: '' }
form.valid                   // true/false
form.get('email')?.errors    // null or { required: true }
form.get('email')?.touched   // true/false

// FormArray
const phones = form.get('phones') as FormArray;
phones.push(new FormControl(''));
phones.removeAt(0);

HTML
<!-- Template-driven form -->
<form #f="ngForm" (ngSubmit)="onSubmit(f)">
  <input name="email" ngModel required email />
  <button [disabled]="f.invalid">Submit</button>
</form>

<!-- Reactive form -->
<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <input formControlName="email" />
  <input formControlName="password" />
  <div formGroupName="address">
    <input formControlName="city" />
  </div>
  <button [disabled]="form.invalid">Submit</button>
</form>
HTTP Client

TS
private http = inject(HttpClient);

// GET
http.get<User[]>('/api/users')
http.get<User>(`/api/users/${id}`)
http.get<User[]>('/api/users', { params: { page: '1', limit: '10' } })

// POST
http.post<User>('/api/users', { name: 'Alice', email: 'alice@example.com' })

// PUT / PATCH
http.put<User>(`/api/users/${id}`, updatedUser)
http.patch<User>(`/api/users/${id}`, { name: 'Alice' })

// DELETE
http.delete(`/api/users/${id}`)

// With headers
http.get('/api/data', {
  headers: new HttpHeaders({ Authorization: `Bearer ${token}` }),
})

// Interceptor
export const authInterceptor: HttpInterceptorFn = (req, next) => {
  const token = inject(AuthService).getToken();
  return next(req.clone({ setHeaders: { Authorization: `Bearer ${token}` } }));
};
RxJS Quick Reference

TS
import { of, from, interval, timer, combineLatest, forkJoin, merge } from 'rxjs';
import { map, filter, switchMap, mergeMap, concatMap, exhaustMap,
         catchError, tap, take, debounceTime, distinctUntilChanged,
         shareReplay, startWith, withLatestFrom } from 'rxjs/operators';

// Creation
of(1, 2, 3)                  // Emit values synchronously
from([1, 2, 3])              // From array/promise
interval(1000)               // Emit 0,1,2... every second
timer(1000, 500)             // After 1s, then every 500ms

// Transformation
map(x => x * 2)
switchMap(id => http.get(`/api/${id}`))   // Cancel previous, use latest
mergeMap(id => http.get(`/api/${id}`))    // Parallel, all results
concatMap(id => http.get(`/api/${id}`))   // Sequential, in order
exhaustMap(id => http.get(`/api/${id}`))  // Ignore new until current completes

// Filtering
filter(x => x > 0)
take(5)
debounceTime(300)
distinctUntilChanged()

// Combination
combineLatest([a$, b$])     // Latest from all, on any change
forkJoin([a$, b$])          // Wait for all to complete
merge(a$, b$)               // Merge multiple streams

// Error handling
catchError(err => of(defaultValue))
retry(3)

// Utility
tap(val => console.log(val))
shareReplay(1)              // Cache and replay last value
Pipes Quick Reference

HTML
<!-- Built-in pipes -->
{{ name | uppercase }}                     <!-- ALICE -->
{{ name | lowercase }}                     <!-- alice -->
{{ name | titlecase }}                     <!-- Alice Smith -->
{{ 'hello world' | slice:0:5 }}           <!-- hello -->

{{ 3.14159 | number:'1.2-2' }}           <!-- 3.14 -->
{{ 1234.56 | currency:'USD' }}           <!-- $1,234.56 -->
{{ 0.25 | percent }}                      <!-- 25% -->

{{ today | date:'shortDate' }}           <!-- 7/1/26 -->
{{ today | date:'fullDate' }}            <!-- Tuesday, July 1, 2026 -->
{{ today | date:'HH:mm:ss' }}           <!-- 14:30:00 -->

{{ items | json }}                        <!-- Debug: pretty-print object -->
{{ observable$ | async }}               <!-- Subscribe + unsubscribe automatically -->

{{ items | keyvalue }}                   <!-- Iterate object key-value pairs -->
{{ items | slice:0:5 }}                  <!-- First 5 items of array -->
CLI Commands

Bash
# Generate
ng g component features/user-list      # Component
ng g service core/auth                 # Service
ng g directive shared/highlight        # Directive
ng g pipe shared/truncate              # Pipe
ng g guard core/auth --implements CanActivate  # Guard
ng g interceptor core/http/auth        # Interceptor
ng g class models/user --type=model    # Class
ng g interface models/user             # Interface
ng g enum models/status                # Enum

# Flags
ng g component my-comp --standalone --skip-tests
ng g service my-svc --dry-run    # Preview without creating

# Build
ng build                      # Dev build
ng build --configuration=production  # Prod build
ng build --stats-json         # For bundle analysis

# Test
ng test                       # Run tests (watch mode)
ng test --watch=false --code-coverage

# Misc
ng update                     # Update Angular
ng add @angular/material      # Add Angular Material
ng lint                       # Run ESLint