Angular Fundamentals
itWeb development
Angular Fundamentals
Angular is a web framework for building applications with TypeScript, HTML, and CSS. It gives you one integrated system for user interfaces, navigation, forms, server communication, testing, and build tooling.
That integration is Angular's central tradeoff. You adopt more structure than a small view library requires. In return, teams get shared conventions and first-party solutions for common application problems.
Angular works well when an application has many screens, substantial user interaction, or a team that benefits from consistent patterns. A small static page may not need a framework. A content-heavy site may need server rendering or prerendering rather than client-only rendering.
Think in component trees
An Angular application is a tree of components. Each component owns a part of the page and the behavior behind it.
A component has three core parts:
- A TypeScript class holds state and behavior.
- An HTML template describes the rendered view.
- A selector identifies the component in another template.
The @Component decorator adds Angular metadata to the class. Modern Angular components are standalone by default. A standalone component lists the components, directives, and pipes used by its template in its own imports array.
import {Component, signal} from '@angular/core';
@Component({
selector: 'app-counter',
template: `
<button type="button" (click)="increment()">
Count: {{ count() }}
</button>
`,
})
export class Counter {
count = signal(0);
increment() {
this.count.update(value => value + 1);
}
}
This example contains the basic Angular loop. State lives in the class. The template reads that state. An event calls a class method. Angular updates the affected view when the state changes.
Build components around a clear responsibility. A page component can coordinate a route. Smaller components can present a profile, search control, or table. Avoid putting the whole application into one component.
Templates connect state to the DOM
An Angular template is HTML with Angular syntax. Angular compiles templates into JavaScript and keeps rendered output synchronized with application state.
Four template mechanisms cover most early work:
| Mechanism | Syntax | Purpose |
|---|---|---|
| Interpolation | {{ total }} | Render text from an expression |
| Property binding | [disabled]="saving" | Set a DOM or component property |
| Event binding | (click)="save()" | Run code for an event |
| Control flow | @if, @for, @switch | Select or repeat template content |
Use property binding when the target is a property. Use attribute binding when you must set an HTML attribute, including many accessibility attributes. Keep template expressions readable. Move multi-step decisions into the component class or a service.
Templates are executable application code. Do not construct Angular templates from user input. Use Angular bindings so the framework can apply its normal escaping and sanitization rules.
Signals model reactive state
A signal wraps a value and notifies consumers when that value changes. Read a signal by calling it. Update a writable signal with set or update.
A computed signal derives a value from other signals. Angular tracks the signals read during the computation and recalculates when those dependencies change.
import {computed, signal} from '@angular/core';
const price = signal(20);
const quantity = signal(2);
const total = computed(() => price() * quantity());
Use writable signals for owned state. Use computed signals for derived state. Do not copy a derived value into a second writable signal. Two writable copies can disagree.
An effect runs side-effecting code when its signal dependencies change. Effects are useful at boundaries such as logging or integration with a non-Angular API. They are not the default tool for propagating state. Prefer computed for derivation.
Angular also uses other asynchronous abstractions. HttpClient methods return RxJS observables. Router and form APIs expose event streams. Signals and observables solve related but different problems, so learn the boundary between current state and asynchronous event sequences.
Inputs, outputs, and services define boundaries
Components need explicit boundaries. An input carries data from a parent into a child. An output reports an event from a child to a parent. This keeps the component tree understandable.
Do not route every interaction through distant shared state. Keep state close to the component that owns it. Lift state to a parent when siblings must coordinate. Move non-visual behavior into a service when several components need it.
A service is a class that provides shared behavior or data access. Angular's dependency injection system supplies dependencies to a class instead of making the class construct them.
import {Component, inject} from '@angular/core';
import {OrderService} from './order.service';
@Component({
selector: 'app-orders',
template: `...`,
})
export class Orders {
private orders = inject(OrderService);
}
Dependency injection separates use from construction. Production code can receive the real service. A test can provide a controlled replacement. Provider scope also determines whether consumers share an instance or receive a more local instance.
The router maps URLs to views
Angular Router is the framework's navigation library. A route maps a URL pattern to a component or other routing behavior. A router outlet marks where the active routed component renders. Router links initiate navigation without a full page reload in a client-rendered application.
Routes can also carry parameters, load code lazily, resolve data, and run guards. Treat route guards as navigation controls, not security boundaries. A server must still authorize every protected operation because browser code can be modified or bypassed.
Design URLs as stable application state. A useful URL can be bookmarked, shared, refreshed, and interpreted without hidden navigation history.
Forms make user input explicit
Current Angular documentation presents three form approaches:
- Signal Forms use a signal-backed model and schema-based validation.
- Reactive Forms define an explicit form-control model in TypeScript.
- Template-driven Forms create much of the form model through template directives.
Reactive Forms remain a strong foundation for complex forms because their model is explicit, synchronous, reusable, and testable. Template-driven Forms fit small forms whose logic stays simple. Evaluate Signal Forms from the current documentation when a signal-native model fits the application.
All approaches still require accessible labels, useful error messages, correct validation, and server-side validation. Client-side validation improves feedback. It does not establish trust.
HTTP belongs behind a data boundary
HttpClient provides typed requests, interception, error handling, and testing utilities. Inject it into a service that represents a backend capability. Keep transport details out of presentation components when possible.
An HTTP request does not run merely because code creates an observable. HttpClient observables are cold. Each subscription sends a request. Control subscription ownership so repeated template rendering or duplicated subscriptions do not create unintended traffic.
Interceptors can apply cross-cutting behavior such as authentication headers, tracing, or consistent error handling. They should not hide business decisions that callers need to understand.
The browser still enforces web security rules. Angular does not remove the need for HTTPS, server authorization, Cross-Origin Resource Sharing policy, or secure session design.
Rendering is an architectural decision
Angular supports several rendering modes:
- Client-side rendering sends application code and renders in the browser.
- Server-side rendering creates HTML for a request on the server.
- Prerendering creates static HTML during the build.
- Hybrid rendering selects a mode for different routes.
Server-rendered HTML can improve initial display and indexing for suitable pages. Hydration restores Angular behavior while reusing server-rendered DOM. Browser-only code must run at an appropriate browser lifecycle boundary. Server and client output must remain consistent to avoid hydration mismatches.
Choose rendering per route and workload. An authenticated dashboard can favor client rendering. Public product or documentation pages may benefit from server rendering or prerendering. Rendering mode does not replace caching, performance measurement, or backend design.
Testing checks behavior at useful boundaries
New Angular CLI projects use Vitest for unit testing. Angular's TestBed creates a configured Angular test environment. A component test should check the class and template together when rendered behavior matters.
Use the router testing harness for routed behavior. Use Angular's HTTP testing backend to capture requests and provide controlled responses. These tools keep tests at the framework boundary instead of making real navigation or network calls.
Test user-visible behavior and important state transitions. Avoid tests that only repeat private implementation details. A stable test explains what the application promises.
Accessibility and security are design inputs
Start with native HTML elements. A real button already has keyboard and activation behavior. Add Accessible Rich Internet Applications attributes only when native semantics do not express the interface.
Manage focus after route navigation. Label form controls. Announce important asynchronous changes when needed. Angular CDK and Angular Aria provide tools for advanced interaction patterns, but they do not replace semantic design and testing with assistive technology.
Angular treats bound values as untrusted and sanitizes them according to their DOM context. Bypass APIs disable part of that protection and require a security review. Prefer templates over direct DOM manipulation. Add Content Security Policy and Trusted Types as defense-in-depth controls where the deployment supports them.
Angular covers framework-level protections. Your application still owns authentication, authorization, data validation, dependency maintenance, and secure server behavior.
A practical learning path
- Build a standalone component and compose it into a component tree.
- Practice interpolation, property binding, events, and template control flow.
- Model local state with writable and computed signals.
- Move shared behavior into injected services.
- Add routes with stable URLs and lazy boundaries.
- Build and validate a form using the approach chosen for its complexity.
- Put
HttpClientbehind a data service and test its request behavior. - Test components and navigation through Angular's testing utilities.
- Review accessibility, security, rendering, and performance before release.
- Use the official guides and API reference for details beyond this orientation.
