What is Angular?
Angular is a component-based TypeScript framework for building scalable single-page web applications, developed and maintained by Google. Unlike a thin UI library, Angular ships with everything a real application needs out of the box: a component model, a powerful template syntax, dependency injection, routing, forms, and an HTTP client. This page introduces what Angular is, what it is used for, and how the modern framework (v17 and later) differs from the legacy AngularJS it replaced.
A complete, opinionated framework
Where some tools hand you only a rendering primitive and leave the rest to the ecosystem, Angular is a framework: it provides a structured, batteries-included platform with official, well-integrated answers to the common problems of app development. Routing, form handling, HTTP communication, and dependency injection all ship as first-party packages designed to work together.
That structure is the trade-off. Angular is more opinionated and has a larger initial surface area than a minimal library, but in return large teams get consistency, strong tooling, and conventions that keep big codebases maintainable. Everything is written in TypeScript, so you get static types, autocompletion, and refactoring safety across the whole stack.
Components and templates
The building block of every Angular app is the component: a TypeScript class paired with an HTML template and styles. Modern Angular uses standalone components by default — components declare their own dependencies via the imports array, so the old NgModule boilerplate is no longer required.
import { Component } from '@angular/core';
@Component({
selector: 'app-greeting',
standalone: true,
template: `<h1>Hello, {{ name }}!</h1>`,
})
export class GreetingComponent {
name = 'Ada';
}
The {{ name }} syntax is interpolation — it binds the class property into the rendered DOM. When name changes, Angular updates the view for you; you never touch the DOM by hand.
Signals: modern reactivity
Recent Angular introduces signals, a fine-grained reactive primitive for holding and deriving state. A signal is a value you read by calling it, and templates that read a signal update automatically when it changes.
import { Component, signal, computed } from '@angular/core';
@Component({
selector: 'app-counter',
standalone: true,
template: `
<p>Count: {{ count() }} — doubled: {{ doubled() }}</p>
<button (click)="increment()">Increment</button>
`,
})
export class CounterComponent {
count = signal(0);
doubled = computed(() => this.count() * 2);
increment() {
this.count.update((n) => n + 1);
}
}
(click) is event binding, and computed() derives a value that recalculates only when its dependencies change — the foundation of efficient, predictable updates in modern Angular.
The new control flow syntax
Modern templates use built-in control flow blocks — @if, @for, and @switch — which replace the older *ngIf and *ngFor structural directives. The new syntax is faster, type-checked, and needs no imports.
@if (user(); as u) {
<p>Welcome back, {{ u.name }}</p>
} @else {
<p>Please sign in</p>
}
<ul>
@for (item of items(); track item.id) {
<li>{{ item.label }}</li>
} @empty {
<li>No items yet</li>
}
</ul>
The mandatory track expression tells Angular how to identify items, so list updates reuse DOM nodes efficiently instead of re-rendering the whole list.
Dependency injection and services
Angular has a built-in dependency injection system. Shared logic lives in services, which components request rather than construct. The modern inject() function makes this concise and works in functional guards and interceptors too.
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({ providedIn: 'root' })
export class UserService {
private http = inject(HttpClient);
getUsers() {
return this.http.get<User[]>('/api/users');
}
}
providedIn: 'root' registers a single shared instance app-wide, so any component can inject(UserService) and get the same object.
Modern Angular vs legacy AngularJS
AngularJS (version 1.x, released in 2010) and Angular (the complete rewrite from version 2 onward) are different frameworks that share only a name. New projects should always use modern Angular.
| Aspect | AngularJS (1.x) | Modern Angular (17+) |
|---|---|---|
| Language | JavaScript | TypeScript |
| Architecture | Controllers, $scope, directives | Standalone components |
| Reactivity | Dirty-checking digest cycle | Signals + zoneless option |
| Templates | ng-if, ng-repeat | @if, @for, @switch |
| Module system | Custom DI modules | ES modules + standalone APIs |
| Tooling | Manual / Bower | Angular CLI + esbuild |
| Status | End of life | Actively developed |
Note: “Angular” with no version number always means the modern framework. The name “AngularJS” refers only to the deprecated 1.x line, which reached end of life in 2022.
What you can build
Because Angular bundles routing, forms, and HTTP support, it suits ambitious, long-lived applications:
- Enterprise single-page applications — dashboards, admin consoles, and internal tools with complex state.
- Progressive web apps — installable, offline-capable apps using the official service-worker package.
- Server-side rendered sites — fast, SEO-friendly pages via Angular SSR and hydration.
- Large multi-team codebases — where strong conventions and TypeScript keep growth manageable.
Best practices
- Start every new project with standalone components and skip
NgModuleentirely. - Use signals and
computed()for component state instead of manual change-detection juggling. - Prefer the new
@if/@for/@switchcontrol flow over the legacy*ngIf/*ngFordirectives, and always provide atrackexpression in@for. - Inject dependencies with
inject()and keep shared logic inprovidedIn: 'root'services. - Write everything in TypeScript with
strictmode enabled to catch errors at compile time. - Lean on the Angular CLI for scaffolding, building, and testing rather than hand-wiring tooling.