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
| Topic | What it covers | |
|---|---|---|
| Components and templates | Standalone components, signal-based state, inputs and outputs, and the built-in template control flow | lesson |
| Services and dependency injection | Injectable services, the inject() function, providers and tokens, plus an HTTP layer with interceptors and typed | lesson |
| Routing and forms | Route configuration with lazy loading and functional guards, then typed reactive forms with validation that the user | lesson |
| Setting up a workspace with the Angular CLI | Set strict in tsconfig.json on day one. Turning on strictTemplates later is a large refactor, and it is the check that | lesson |
| Template control flow, pipes and deferred views | Use the built-in control flow blocks, keep pipes pure, and split a heavy page with @defer so the first paint is not | lesson |
| HTTP, interceptors and async resources | Interceptors run in registration order on the way out and in reverse order on the way back, so the array order is | lesson |
| Advanced reactive and signal forms | Signal forms are converging on a different model where the field tree is a set of signal nodes with their own state | lesson |
| Change detection, zoneless and performance | Zone.js patches every asynchronous browser API so Angular knows when something might have changed, then checks the | lesson |
| Testing Angular applications | TestBed with standalone components, component harnesses, HttpTestingController, and how to test signal and zoneless | lesson |
| Server rendering, hydration and deployment | Turn on rendering, control it per route, avoid the platform traps, and choose a hosting model that matches how you | lesson |
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 metadataFull 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 falseFull 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.htmlFull 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?
Where do the examples come from?
How do I go deeper than a cheat sheet?
Related cheat sheets
HTML CSS JavaScript TypeScript HTML DOM AJAX
Last refreshed 2026-09-27.