Angular cheat sheet

A scannable Angular reference: 17 short snippets across 10 topics, each linking back to the lesson it came from.

At a glance

TopicWhat it covers
Components and templatesStandalone components, signal-based state, inputs and outputs, and the built-in template control flowlesson
Services and dependency injectionInjectable services, the inject() function, providers and tokens, plus an HTTP layer with interceptors and typedlesson
Routing and formsRoute configuration with lazy loading and functional guards, then typed reactive forms with validation that the userlesson
Setting up a workspace with the Angular CLISet strict in tsconfig.json on day one. Turning on strictTemplates later is a large refactor, and it is the check thatlesson
Template control flow, pipes and deferred viewsUse the built-in control flow blocks, keep pipes pure, and split a heavy page with @defer so the first paint is notlesson
HTTP, interceptors and async resourcesInterceptors run in registration order on the way out and in reverse order on the way back, so the array order islesson
Advanced reactive and signal formsSignal forms are converging on a different model where the field tree is a set of signal nodes with their own statelesson
Change detection, zoneless and performanceZone.js patches every asynchronous browser API so Angular knows when something might have changed, then checks thelesson
Testing Angular applicationsTestBed with standalone components, component harnesses, HttpTestingController, and how to test signal and zonelesslesson
Server rendering, hydration and deploymentTurn on rendering, control it per route, avoid the platform traps, and choose a hosting model that matches how youlesson

Quick snippets

Components and templates

A standalone component

npm install -g @angular/cli
ng new shop --style=scss --routing
cd shop && ng serve            # dev server on http://localhost:4200

ng generate component cart/item     # creates the four files for one component
ng generate service cart            # service skeleton with injectable metadata

Full lesson: Components and templates →

Services and dependency injection

Writing and consuming a service

import { Component, inject } from '@angular/core'
import { CartStore } from './cart.store'

@Component({ selector: 'app-cart', template: '{{ cart.total() }}' })
export class CartComponent {
  readonly cart = inject(CartStore)     // resolved from the injector, no constructor ceremony
}

Providers, tokens and overrides

// a component-level override, useful in tests and previews
@Component({
  selector: 'app-preview',
  providers: [{ provide: API_BASE, useValue: 'https://staging.example.com' }],
  template: '...'
})
export class PreviewComponent {}

// in a unit test
TestBed.configureTestingModule({
  providers: [{ provide: CartStore, useValue: fakeCart }]
})

HTTP with interceptors

// auth.interceptor.ts — functional interceptor, registered in app.config.ts
import { HttpInterceptorFn } from '@angular/common/http'

export const authInterceptor: HttpInterceptorFn = (req, next) => {
  const token = localStorage.getItem('token')
  if (!token || req.url.startsWith('https://cdn.')) return next(req)

  return next(req.clone({ setHeaders: { Authorization: 'Bearer ' + token } }))
}

Full lesson: Services and dependency injection →

Routing and forms

Routes, lazy loading and guards

// main.ts
import { bootstrapApplication } from '@angular/platform-browser'
import { provideRouter, withComponentInputBinding, withInMemoryScrolling } from '@angular/router'

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(routes, withComponentInputBinding(), withInMemoryScrolling({ scrollPositionRestoration: 'top' }))
  ]
})

Typed reactive forms

<form [formGroup]="form" (ngSubmit)="submit()">
  <label for="email">Email</label>
  <input id="email" type="email" formControlName="email"
         [attr.aria-invalid]="form.controls.email.invalid && form.controls.email.touched" />

  @if (form.controls.email.touched && form.controls.email.hasError('email')) {
    <p class="error">Enter a valid email address.</p>
  }

  <button type="submit" [disabled]="form.invalid">Create account</button>
</form>

Full lesson: Routing and forms →

Setting up a workspace with the Angular CLI

ng generate and budgets

ng generate component invoices/invoice-list
ng g c shared/ui/stat-card --change-detection=OnPush --skip-tests
ng g s core/auth
ng g guard core/require-auth          # a functional CanActivateFn
ng g interceptor core/auth
ng g environment

ng g c invoices/invoice-list --dry-run  # print the plan, write nothing
ng config schematics.@schematics/angular:component.changeDetection OnPush
ng config cli.analytics false

Full lesson: Setting up a workspace with the Angular CLI →

Template control flow, pipes and deferred views

Pipes and their gotchas

<p>{{ invoice.createdAt | date: 'mediumDate' }}</p>
<p>{{ total | currency: 'EUR' : 'symbol' : '1.2-2' }}</p>
<p>{{ description | slice: 0 : 120 }}{{ (description | slice: 120).length ? '…' : '' }}</p>
<p>{{ invoice.createdAt | timeAgo }}</p>

<!-- async pipe: one subscription, unsubscribed automatically on destroy -->
@if (invoices$ | async; as invoices) {
  <p>{{ invoices.length }} invoices</p>
}

Pipes and their gotchas

// An impure pipe runs on every change detection pass — usually a bug.
@Pipe({ name: 'filter', standalone: true, pure: false })
export class FilterPipe implements PipeTransform {
  transform(items: Item[], term: string) {
    return items.filter((i) => i.name.toLowerCase().includes(term.toLowerCase()));
  }
}

// Prefer a computed instead: it caches and it is obviously a data concern.
// readonly visible = computed(() =>
//   this.items().filter((i) => i.name.toLowerCase().includes(this.term().toLowerCase())));

Deferred views with @defer

// The deferred component must be a real, separately-loadable boundary.
@Component({
  selector: 'app-revenue-chart',
  standalone: true,
  imports: [BaseChartDirective],       // keeps the chart library out of the initial bundle
  template: `<canvas baseChart [data]="data()"></canvas>`
})
export class RevenueChartComponent {
  readonly data = input.required<ChartData>();
}

Full lesson: Template control flow, pipes and deferred views →

HTTP, interceptors and async resources

provideHttpClient and typed calls

// app.config.ts
import { provideHttpClient, withFetch, withInterceptors, withRequestsMadeViaParent } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(
      withFetch(),                                  // use fetch instead of XHR
      withInterceptors([authInterceptor, retryInterceptor, loggingInterceptor])
    )
  ]
};

Full lesson: HTTP, interceptors and async resources →

Advanced reactive and signal forms

Custom controls with ControlValueAccessor

<!-- Any custom control now behaves like a built-in one -->
<form [formGroup]="reviewForm">
  <app-star-rating formControlName="rating" [required]="true" />
  @if (reviewForm.get('rating')?.invalid && reviewForm.get('rating')?.touched) {
    <p class="error">Please give a rating.</p>
  }
</form>

Full lesson: Advanced reactive and signal forms →

Change detection, zoneless and performance

OnPush and view boundaries

<!-- Slice a hot list: only the changed row is re-rendered -->
@for (row of rows(); track row.id) {
  <app-row [row]="row" (select)="select(row.id)" />
}

Profiling and budgets

# Production build with a stats file for bundle inspection
ng build --configuration production --stats-json
npx source-map-explorer dist/billing-portal/browser/*.js

# Check whether a dependency pulled in something unexpected
npx esbuild-visualizer --metadata dist/*/stats.json

# Find the components that dominate the initial bundle
grep -o 'chunk-[A-Z0-9]*.js' dist/billing-portal/browser/index.html

Full lesson: Change detection, zoneless and performance →

Testing Angular applications

TestBed with standalone components

// Prefer overriding what the component injects over mocking the whole world.
TestBed.overrideComponent(InvoiceListComponent, {
  set: {
    providers: [{ provide: InvoiceApi, useValue: fakeApi }],
    imports: [InvoiceListComponent],   // required when overriding for a standalone component
    template: `<p>stubbed</p>`         // only if you truly need to ignore the real template
  }
});

Full lesson: Testing Angular applications →

Server rendering, hydration and deployment

Enabling rendering and hydration

ng add @angular/ssr          # adds server.ts, app.config.server.ts and build targets
ng build                     # emits browser/ and server/ output
ng run billing-portal:serve  # runs the Node server on the built output
ng serve                     # SSR in development, with live reload

# prerender specific routes at build time
ng build --prerender

Deployment models

// app.config.ts — hydration with event replay
import { provideClientHydration, withEventReplay, withIncrementalHydration } from '@angular/platform-browser';

export const appConfig: ApplicationConfig = {
  providers: [
    provideClientHydration(withEventReplay(), withIncrementalHydration())
  ]
};

Full lesson: Server rendering, hydration and deployment →

FAQ

Is this Angular cheat sheet free to use?
Yes. No sign-up and no tracking: the page is static, every example is on the page itself, and you can print it or save it as a one-page reference.
Where do the examples come from?
Every snippet is taken from the 10 lessons of the Angular course on this site, and each section links back to the lesson it was pulled from.
How do I go deeper than a cheat sheet?
Open the full Angular course — it carries the worked explanations, the edge cases and the exercises behind every line here.

HTML CSS JavaScript TypeScript HTML DOM AJAX

Last refreshed 2026-09-27.