Use this Angular reference after learning the concepts, not as a substitute for them. The snippets are organized by bootstrapping, component metadata, templates, reactivity, routing, forms, and HTTP so the correct ownership boundary remains visible.
Current Angular applications normally start with a standalone root component and an ApplicationConfig. Keep app-wide providers in app.config.ts so routing, HTTP, hydration, and error handling have one visible composition point.
| Syntax | Purpose |
|---|---|
| bootstrapApplication(AppComponent, appConfig) | Starts a standalone application with root providers. |
| provideRouter(routes) | Registers routes and router services. |
| provideHttpClient(withInterceptors([...])) | Registers HttpClient and functional interceptors. |
| provideZonelessChangeDetection() | Configures zoneless change detection explicitly when the application setup needs it. |
Decorators tell Angular which classes participate in templates and dependency injection. Modern components, directives, and pipes are standalone by default; use imports on the consuming component to make template dependencies available.
| Decorator | Role |
|---|---|
| @Component({...}); | Declares a component with a selector, template, styles, imports, providers, and change-detection options. |
| @Directive({...}); | Declares behavior attached to matching host elements. |
| @Pipe({...}); | Declares a reusable template value transformation. |
| @Injectable({...}); | Marks a class for dependency injection metadata and can define its default provider scope. |
NgModules remain supported for existing applications and libraries, but new code can usually compose standalone components directly. Do not add a feature NgModule merely to group files; add one only when an integration or existing architecture requires it.
| NgModule field | Meaning |
|---|---|
| @NgModule({declarations: [], imports: [], exports: [], providers: [], bootstrap: []}); | Defines a compatibility module and its compilation and provider scope. |
| declarations: [MyFirstComponent, MySecondComponent, MyDatePipe] | Lists non-standalone components, directives, and pipes owned by this module. |
| imports: [BrowserModule, MyModule] | Makes exported declarations and standalone dependencies available in this module. |
| exports: [MyFirstComponent, MyDatePipe] | Exposes declarations or imported dependencies to consumers. |
| providers: [MyFirstService, { provide: ... }] | Registers providers in the module injector. |
| bootstrap: [MyAppComponent] | Names the root component only in an application bootstrapped through an NgModule. |
Templates read component state, bind DOM properties, listen for events, and control which views exist. Call signals to read them and always give @for a stable tracking expression.
| Template syntax | Meaning |
|---|---|
| {{ total() | currency }} | Interpolates a signal value after applying a pipe. |
| [disabled]="form.invalid" | Binds an element property. |
| (click)="save()" | Handles a DOM event. |
| [(ngModel)]="name" | Combines value input and change output; requires FormsModule. |
| [attr.aria-label]="label()" | Binds an attribute when no matching DOM property exists. |
Use writable signals for owned state, computed for derived state, and effect only for synchronization with a non-reactive system. A computed signal is read-only because its value belongs to its dependencies.
| Signals API | Purpose |
|---|---|
| count = signal(0) | Creates writable state; read with count(). |
| count.set(5) | Replaces the current signal value. |
| count.update(value => value + 1) | Calculates a replacement from the current value. |
| double = computed(() => count() * 2) | Creates memoized, read-only derived state. |
| effect(() => console.log(count())) | Runs a side effect when tracked signals change; requires an injection context by default. |
| Control flow | Use |
|---|---|
| @if (condition) { } @else { } | Renders one conditional branch. |
| @for (item of items; track item.id) { } | Repeats a view and tracks identity by item.id. |
| @switch (val) { @case (x) { } @default { } } | Selects one matching branch. |
| @defer { } @loading { } @placeholder { } @error { } | Defers noncritical template dependencies and supplies loading states. |
| @let name = expression; | Stores a template expression for reuse in the current view. |
Signals hold synchronously readable reactive values. Calling a signal records a dependency inside templates, computed values, linked signals, effects, and resource parameter functions.
Use writable signals for owned state, computed for read-only derivation, linkedSignal for writable state that resets or reconciles when a source changes, and effects only for synchronization with non-reactive APIs.
A writable signal always has a current value. Read it by calling the signal, replace it with set, or calculate a replacement from the previous value with update.
| Syntax | Purpose |
|---|---|
| count = signal(0) | Creates WritableSignal<number> with current value 0. |
| count() | Reads the current value and tracks the dependency in a reactive context. |
| count.set(5) | Replaces the current value with 5. |
| count.update(value => value + 1) | Calculates the next value from the current value. |
| count.asReadonly() | Exposes a read-only signal view; it does not prevent deep mutation inside an object. |
| signal(value, { equal }) | Uses a custom equality function instead of the default Object.is comparison. |
computed is lazy, memoized, and read-only. linkedSignal is writable but recalculates from its source when that source changes, which suits selections that must remain valid when available options change.
| Syntax | Purpose |
|---|---|
| total = computed(() => price() * quantity()) | Derives a cached read-only value from tracked signals. |
| selected = linkedSignal(() => options()[0]) | Creates writable dependent state that resets when its tracked source changes. |
| linkedSignal({ source, computation }) | Reconciles a source change with the previous source and linked value. |
| untracked(counter) | Reads a signal inside a reactive function without adding that read as a dependency. |
import { computed, linkedSignal, signal } from '@angular/core';
const plans = signal(['Basic', 'Pro']);
const selectedPlan = linkedSignal(() => plans()[0]);
const seats = signal(2);
const monthlyPrice = computed(() =>
selectedPlan() === 'Pro' ? seats() * 20 : seats() * 8
);
selectedPlan.set('Pro');
seats.update(value => value + 1);
console.log(monthlyPrice()); // 60
60
selectedPlan remains user-writable but resets to a valid default if plans changes. monthlyPrice is derived and therefore cannot be set directly.
effect tracks synchronous signal reads and reruns when those dependencies change. Reach for it after computed or linkedSignal because effects are for imperative synchronization, not copying reactive state between signals.
| Syntax | Purpose |
|---|---|
| effect(() => storage.setItem('theme', theme())) | Synchronizes signal state with a non-reactive API. |
| effect(onCleanup => { ... }) | Registers cleanup before the next run or destruction. |
| EffectRef.destroy() | Manually destroys an effect created with an intentional manual lifetime. |
| afterRenderEffect(() => chart.update(data())) | Synchronizes a DOM library after Angular commits rendered changes; client only. |
resource connects reactive parameters to an asynchronous loader while exposing value and status as signals. When parameters change, Angular can abort obsolete loader work through the supplied AbortSignal.
| Syntax | Purpose |
|---|---|
| resource({ params: () => ({ id: id() }), loader }) | Runs the async loader whenever the reactive parameter value changes. |
| user.value() | Reads the latest resource value; guard error or missing states first. |
| user.hasValue() | Checks for a usable value and narrows its type. |
| user.status() | Reads idle, loading, reloading, resolved, local, or error status. |
| user.error() | Reads the loader failure when the resource is in an error state. |
| user.reload() | Requests the current parameters again. |
Angular component APIs use signals for reactive inputs, two-way models, and child queries. Outputs are typed emitters rather than signals, but they complete the modern component communication set.
| Syntax | Purpose |
|---|---|
| value = input(0) | Declares a read-only InputSignal with a default. |
| id = input.required<number>() | Declares an input Angular requires at build time. |
| label = input('', { transform: trimString }) | Transforms an assigned input with a statically analyzable pure function. |
| value = model(0) | Declares writable component state supporting [(value)] two-way binding. |
| saved = output<Order>() | Declares a typed custom event emitted with saved.emit(order). |
| viewChild.required<ElementRef>('field') | Creates a required reactive query for the component view. |
| contentChildren(ItemDirective) | Creates a signal containing matching projected children. |
Keep streams as Observables while cancellation and operator composition are central. Convert once at a component or service boundary when synchronous signal reads make the consumer clearer.
| Syntax | Purpose |
|---|---|
| toSignal(source$, { initialValue: [] }) | Subscribes immediately and exposes the latest Observable value as a signal. |
| toSignal(subject$, { requireSync: true }) | Requires a source such as BehaviorSubject to emit synchronously. |
| toObservable(query) | Creates an Observable that emits tracked signal values. |
| takeUntilDestroyed() | Completes an RxJS chain when the current destruction context ends. |
| outputFromObservable(source$) | Exposes an Observable as a component output. |
| outputToObservable(saved) | Converts an OutputRef to an Observable. |
Inputs pass data into a child; outputs report events out. Model creates a two-way component binding when the child truly owns an editable value.
| Syntax | Purpose |
|---|---|
| name = input('Guest') | Optional signal input with a default value. |
| id = input.required<number>() | Required signal input checked by Angular. |
| saved = output<Order>() | Typed event; emit with saved.emit(order). |
| value = model(0) | Writable input/output pair for [(value)] binding. |
| viewChild.required<ElementRef>('field') | Required signal query for the component view. |
| contentChildren(ItemDirective) | Reactive array of matching projected children. |
inject reads a token from the active injector. Service lifetime is controlled by where the provider is registered.
| Syntax | Scope or behavior |
|---|---|
| private api = inject(ApiService) | Resolves the nearest ApiService provider. |
| @Injectable({ providedIn: 'root' }) | Defines a tree-shakable application-wide service by default. |
| providers: [CartService] | Creates a provider at this component or route boundary. |
| { provide: API_URL, useValue: '/api' } | Supplies a value for an InjectionToken. |
| inject(Logger, { optional: true }) | Returns null when the token is unavailable. |
A route maps a URL to a component or lazy loader. Use RouterLink for internal navigation and router-outlet for the active route view.
| Syntax | Purpose |
|---|---|
| { path: 'products/:id', component: ProductPage } | Declares a parameterized route. |
| loadComponent: () => import('./admin').then(m => m.AdminPage) | Lazy-loads a standalone route component. |
| <a routerLink="/products" routerLinkActive="active"> | Navigates and styles the active link. |
| <router-outlet /> | Renders the active route component. |
| inject(Router).navigate(['/orders', id]) | Navigates from TypeScript. |
| canActivate: [authGuard] | Controls client navigation; never replaces server authorization. |
Reactive forms keep the model in TypeScript. Signal Forms are stable in Angular 22 and suit signal-first form state; template-driven forms remain useful for small forms.
| Syntax | Purpose |
|---|---|
| new FormControl('', { nonNullable: true }) | Creates a typed non-nullable control. |
| fb.group({ email: ['', [Validators.required]] }) | Builds a reactive form group with validation. |
| [formGroup]="profile" and formControlName="email" | Connects reactive controls to a template. |
| control.invalid && (control.dirty || control.touched) | Shows errors after interaction. |
| form(loginModel) | Creates a Signal Form tree from a writable model signal. |
| [field]="loginForm.email" | Binds a Signal Form field to an input. |
HttpClient methods return cold Observables: a request begins on subscription. Handle a failure where the application can make a useful recovery decision.
| Syntax | Purpose |
|---|---|
| http.get<Product[]>('/api/products') | Issues a typed GET request when subscribed. |
| http.post<Order>('/api/orders', body) | Sends a body and types the response. |
| withInterceptors([authInterceptor]) | Registers functional interceptors. |
| source$.pipe(map(...), switchMap(...), catchError(...)) | Transforms, switches work, and handles failures. |
| takeUntilDestroyed() | Completes a subscription at destruction. |
| toSignal(source$, { initialValue: [] }) | Exposes the latest Observable value as a signal. |
Hooks are timing boundaries, not a checklist to implement on every component.
| API | Use |
|---|---|
| ngOnChanges | Respond to input assignments; its first run precedes ngOnInit. |
| ngOnInit | Run one-time setup after initial inputs. |
| ngAfterContentInit | Read initialized projected-content queries. |
| ngAfterViewInit | Read initialized component-view queries. |
| afterNextRender | Perform browser DOM work after the next full render. |
| ngOnDestroy / DestroyRef | Release resources before destruction. |
Run CLI commands from the workspace root. New Angular projects use Vitest with jsdom by default; migrated repositories may retain another runner.
| Command or API | Purpose |
|---|---|
| ng new store --routing --style=scss | Creates a routed workspace with SCSS. |
| ng generate component product-card | Generates a component and test. |
| ng serve | Starts the development server. |
| ng test | Runs the configured unit tests. |
| ng build | Creates the production build. |
| TestBed.createComponent(ProductCard) | Creates a component fixture. |
| fixture.detectChanges() | Runs binding and change detection in the test. |
Angular escapes interpolation and sanitizes supported binding contexts, but application design still controls trust, authorization, and performance.
Directives add behavior or structure to existing elements. Pipes transform a value for display without changing the source value.
Import a directive into a standalone component before using it. The @if, @for, and @switch blocks are built-in template control flow and do not require CommonModule imports.
| API | Use |
|---|---|
| [class.active]="selected" | Toggles one CSS class; prefer this over NgClass for a single class. |
| [style.width.px]="width" | Sets one style property with an optional unit. |
| [ngClass]="classMap" | Adds or removes several classes from a string, array, or object expression. |
| [ngStyle]="styleMap" | Sets several inline styles from an object. |
| [(ngModel)]="name" | Adds two-way binding to a form control; import FormsModule. |
| NgOptimizedImage | Adds image loading and performance guidance through the ngSrc API. |
Create an attribute directive with @Directive when behavior belongs on an existing host element. Prefer the host metadata object for host bindings and listeners, and expose configuration with input or input.required.
| Syntax | Purpose |
|---|---|
| @Directive({ selector: '[appAutofocus]' }) | Matches elements carrying the appAutofocus attribute. |
| host: { '(focus)': 'onFocus()' } | Declares host events, properties, attributes, classes, or styles. |
| delay = input(0) | Accepts typed configuration from the host template. |
| hostDirectives: [MenuBehavior] | Composes directive behavior into a component or another directive. |
Pipes can be chained from left to right and can accept colon-separated arguments. Import each pipe used by a standalone component.
| Pipe | Use |
|---|---|
| async | Reads the latest Promise or Observable value and manages the subscription. |
| currency / decimal / percent | Formats numbers using locale-aware rules. |
| date | Formats a date with optional format, timezone, and locale arguments. |
| json | Displays JSON.stringify output for debugging, not polished user content. |
| keyvalue | Turns an Object or Map into iterable key-value pairs. |
| slice | Returns a subset of an Array or String. |
| titlecase / uppercase / lowercase | Changes text casing for display. |
A custom pipe uses @Pipe and implements PipeTransform.transform. Pipes are pure by default, so an object or array must receive a new reference before the pipe runs again.
Avoid pure: false unless repeated execution is essential and measured; an impure pipe may run frequently during change detection.
| Syntax | Purpose |
|---|---|
| @Pipe({ name: 'initials' }) | Registers the template name used after the pipe operator. |
| transform(value, argument) | Receives the input value and optional pipe arguments, then returns the display value. |
| {{ name | initials:2 }} | Passes name as the value and 2 as an argument. |
Change detection evaluates template bindings and updates the DOM. Start with signals, immutable updates, and the framework scheduler; use manual ChangeDetectorRef controls only for a measured integration need.
Default components are checked during the normal application traversal. OnPush lets Angular skip an unchanged subtree until it receives a new input, handles an event in the subtree, is explicitly marked, or a template dependency such as a signal notifies Angular.
| API or event | Effect |
|---|---|
| changeDetection: ChangeDetectionStrategy.OnPush | Enables subtree skipping when Angular has no relevant notification. |
| input reference changes | Schedules the OnPush component when Angular binds a different value. |
| signal read in a template changes | Marks the consuming component so the new value can render. |
| event handled in the subtree | Runs change detection for the affected view path. |
Use ChangeDetectorRef at integration boundaries where Angular cannot infer the update. Manual calls can hide a broken state flow, so keep them local and document the external trigger.
| API | Use |
|---|---|
| markForCheck() | Marks an OnPush view to participate in a future check. |
| detectChanges() | Checks this view and its children immediately. |
| detach() | Removes a view from the normal change-detection tree. |
| reattach() | Returns a detached view to normal checking. |
| afterNextRender() | Runs one-time DOM work after the next application render. |
| afterRenderEffect() | Runs reactive DOM synchronization after rendering on the client. |
Keep component styles local by default, bind state through classes and styles, and use CSS-based enter and leave animations for UI transitions.
Component metadata accepts inline styles or styleUrl/styleUrls files. Emulated encapsulation scopes selectors by default; ShadowDom uses the browser shadow root; None makes the component styles global.
| Syntax | Use |
|---|---|
| styleUrl: './card.css' | Loads one component stylesheet. |
| encapsulation: ViewEncapsulation.Emulated | Scopes selectors with generated attributes; this is the default. |
| encapsulation: ViewEncapsulation.ShadowDom | Uses native Shadow DOM boundaries. |
| encapsulation: ViewEncapsulation.None | Applies component CSS globally; use deliberate selector names. |
| :host { display: block; } | Styles the component host element. |
animate.enter and animate.leave apply CSS classes while an element enters or leaves the DOM. Angular removes enter classes when the longest animation completes and waits for leave motion before removing the element.
Provide a reduced-motion rule so the interface remains comfortable for users who request less animation.
| Syntax | Use |
|---|---|
| <div animate.enter="fade-in"> | Applies one or more CSS classes while the element enters. |
| <div animate.leave="fade-out"> | Keeps the element long enough for its leave transition or animation. |
| [animate.enter]="enterClass()" | Chooses the animation class from component state. |
| @media (prefers-reduced-motion: reduce) | Removes or shortens nonessential motion for the user preference. |
Angular can render routes in the browser, on a server per request, or ahead of time during the build. Choose per route from freshness, personalization, indexing, and server-cost requirements.
Client-side rendering ships an application shell and renders in the browser. Server-side rendering creates HTML for each request. Prerendering creates reusable HTML files during the build and needs a rebuild when that content changes.
| Mode | Best fit |
|---|---|
| RenderMode.Client | Highly interactive private areas where indexed initial HTML is not required. |
| RenderMode.Server | Personalized or frequently changing public routes that need request-time HTML. |
| RenderMode.Prerender | Stable public routes that can be generated at build time and served cheaply. |
| getPrerenderParams | Supplies build-time parameter combinations for dynamic prerendered routes. |
Hydration reuses server-rendered DOM in the browser instead of rebuilding it. Configure provideClientHydration in the client providers and keep the server and client DOM structure consistent.
Avoid direct DOM rewrites before hydration completes. Use Angular templates and APIs for DOM ownership, or apply ngSkipHydration to a specific incompatible component only as a temporary boundary.
| API | Use |
|---|---|
| provideClientHydration() | Enables DOM reconciliation for a server-rendered application. |
| withEventReplay() | Captures supported user events before hydration and replays them afterward. |
| withIncrementalHydration() | Hydrates deferred sections when their configured trigger occurs and enables event replay. |
| ngSkipHydration | Skips hydration for one incompatible component host; Angular rerenders it on the client. |
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { authInterceptor } from './auth.interceptor';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideHttpClient(withInterceptors([authInterceptor]))
]
};
// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { appConfig } from './app/app.config';
bootstrapApplication(AppComponent, appConfig)
.catch(error => console.error(error));
This is the current standalone composition pattern. Feature components list template dependencies in their own imports; application-wide providers remain in ApplicationConfig.
Treat each table row as a syntax reminder. Add the named import, register providers in ApplicationConfig or the intended injector, and add template dependencies to the component imports before compiling. The standalone skeleton is the complete starting point on this page.
computed represents derived state whose owner is its dependency graph. Change the source writable signals with set or update; Angular invalidates and recalculates the computed value when it is next read.
Do not defer content required for the first meaningful view, critical navigation, accessibility, or immediate user action merely to reduce the initial bundle. Deferral introduces a loading boundary and may cause layout movement if the placeholder has the wrong dimensions.
Explore 500+ free tutorials across 20+ languages and frameworks.