Built-in “superpowers”
Angular ships with a cohesive toolkit that’s designed to interlock: routing for navigation and data
preloading; forms (template-driven and reactive) with powerful validation; HTTP services with
typed APIs, interceptors and error handling; and a robust dependency injection (DI) system with
hierarchical scopes. Crucially, these features use standalone APIs and play nicely with Signals
and functional patterns introduced in recent releases. (angular.dev)
Routing
Declarative routes map URLs to standalone components, with guards/resolvers that can be written as
functions using inject()
-great for composability and testing. Preloading and lazy loading are
first-class, so you fetch only what the user needs. (angular.dev)
Route setup & providers (main.ts)

Functional guard (auth.guard.ts)

(Resolvers are similar: return data before route activation; run behaviour is configurable.) (angular.io)
Forms
Two complementary models:
- Template-driven: minimal code, directives in templates, great for simple forms.
- Reactive: model is defined in TypeScript (
FormGroup
, FormControl
), enabling dynamic rules,
fine-grained validation and straightforward unit testing.
Reactive form (standalone component)

(Template-driven uses FormsModule
with ngModel
; choose per complexity.)
HTTP services
HttpClient
provides typed requests, Observables, streamlined error handling and interceptors for
cross-cutting concerns (auth headers, logging, retry/backoff). Provide it once at bootstrap; attach
interceptors as needed. (angular.dev)
Register HttpClient + interceptor (main.ts)

Functional interceptor (auth.interceptor.ts)

Typed request with error handling (service)

(Interceptors can transform both requests and responses; they’re chainable and composable.) (angular.dev)
Dependency Injection (DI)
Angular’s DI is hierarchical: provide services at the application root, feature, or component level.
Scope where it lives; reap what it caches. Root-provided services are singletons and tree-shakeable
when unused. You can also provide at component level for per-component instances. The inject()
API
lets you grab dependencies in functions (guards, resolvers, interceptors) and class bodies without a
constructor. (angular.dev)
Root service (tree-shakeable)

Component-scoped provider (new instance per host component)

Using inject()
in a function (no class required)

Why this matters
Because these primitives are batteries-included and composable, you spend less time wiring
third-party bits and more time delivering features. Routes fetch what they need; forms validate with
clarity; HTTP concerns centralise behind interceptors; and DI keeps boundaries crisp while enabling
testability. Cohesion breeds velocity.
Key references: standalone components & anatomy; Signals; Router guards/resolvers; HttpClient and
interceptors; DI best practice and hierarchies. (angular.dev)
(Angular v20 is the current active release at time of writing; examples use its recommended patterns.) (angular.dev)