The Complete Interactive Reference
A

AngularJS
& Angular

A comprehensive deep-dive into Google's powerful web frameworks — from the origins of AngularJS to the modern Angular platform.

2009AngularJS Born
2016Angular 2+ Rewrite
19+Major Versions
3M+Weekly Downloads
scroll
01 — Origin Story

A Decade of Evolution

From a weekend project at Google to one of the world's most widely used frontend frameworks.

2009

AngularJS is Born

Misko Hevery and Adam Abrons create Angular as a side project. Hevery rewrites a 17,000-line app in just 1,500 lines using his framework, convincing Google to adopt it internally.

2010

Open Source Release (v0.9)

AngularJS is released publicly on GitHub. It introduces revolutionary concepts like two-way data binding, directives, and dependency injection to the JavaScript world.

2012

AngularJS 1.0 Stable

After years of development, AngularJS 1.0 is officially released. It rapidly becomes the dominant frontend framework, popularizing MVC/MVVM architecture in SPAs.

2014

Angular 2.0 Announced

At ng-Europe, Google announces a complete rewrite of Angular. The announcement causes controversy as it breaks backward compatibility with AngularJS entirely.

2016

Angular 2 Released

Angular 2 launches as a completely new framework built in TypeScript. Component-based architecture replaces controllers/scopes. Modules, decorators, and RxJS become core concepts.

2017

Angular 4 & Semantic Versioning

Angular skips v3 to align router package versions. Introduces semantic versioning with predictable 6-month release cycles. Angular CLI matures significantly.

2020

Angular 9 — Ivy Renderer

Ivy becomes the default rendering engine. Dramatically improves bundle sizes, compilation speed, and debugging. Tree-shaking becomes much more effective.

2022

Angular 14 — Standalone Components

Standalone components, directives, and pipes are introduced, allowing developers to build Angular apps without NgModules. Typed reactive forms also added.

2023

Angular 16–17 — Signals & SSR

Angular Signals introduced as a new reactivity primitive. Angular 17 launches a new documentation site (angular.dev), deferrable views, and major SSR/hydration improvements.

2024+

Angular 18–19 — Zoneless & Modern DX

Experimental zoneless change detection with Signals. Incremental hydration, route-level rendering modes, and resource API preview. Angular continues modernizing its DX.

02 — Core Concepts

The Building Blocks

Click any card to expand it and learn more about each Angular concept.

🧱

Components

The fundamental building block of Angular. A component controls a view — a region of the screen — through a class decorated with @Component.

Key Properties:
selector — CSS selector identifying this component in a template
template/templateUrl — The HTML view
styles/styleUrls — Scoped CSS
standalone: true — Opt out of NgModule (Angular 14+)

Lifecycle: ngOnInit → ngOnChanges → ngDoCheck → ngAfterContentInit → ngAfterViewInit → ngOnDestroy
📋

Templates

Angular's HTML-based template syntax extends HTML with directives, binding, and interpolation to connect the view to the component's data.

Template Syntax:
{{ expression }} — Interpolation
[property]="expr" — Property binding
(event)="handler()" — Event binding
[(ngModel)]="prop" — Two-way binding
*ngIf / *ngFor — Structural directives
@if / @for — New control flow (v17+)
💉

Dependency Injection

Angular's powerful DI system allows services and other dependencies to be injected into components, promoting separation of concerns and testability.

DI Hierarchy:
• Root injector (providedIn: 'root')
• Module injector
• Component injector

Providers: useClass, useValue, useFactory, useExisting
Injection Tokens: InjectionToken for non-class dependencies
inject() function: Functional DI (Angular 14+)
🔧

Services

Singleton classes that provide shared functionality — data fetching, business logic, state management — across multiple components.

Best Practices:
• Decorate with @Injectable()
• Use providedIn: 'root' for app-wide singletons
• Use HttpClient for HTTP requests
• Leverage RxJS Observables for async ops

Tree-shakable providers: Services not used are eliminated from the bundle by Ivy.
🗺️

Modules (NgModule)

Containers that group related components, directives, pipes, and services. The root AppModule bootstraps the application.

NgModule Metadata:
declarations — Components/directives/pipes
imports — Other modules needed
exports — Public API of this module
providers — Services
bootstrap — Root component

Note: Standalone components (Angular 14+) can replace NgModules for simpler architectures.
🛣️

Router

Angular's powerful client-side navigation system enables single-page application routing with lazy loading, guards, and resolvers.

Key Concepts:
RouterModule.forRoot(routes) — Root routing
RouterModule.forChild(routes) — Feature routing
router-outlet — Where routes render
routerLink — Navigation directive
Route Guards: CanActivate, CanDeactivate, CanMatch
Resolvers: Pre-fetch data before navigation
Lazy Loading: loadChildren / loadComponent
🔄

RxJS & Observables

Angular is deeply integrated with RxJS for reactive programming. HTTP requests, events, and state changes flow as observable streams.

Common Operators:
map, filter, tap — Transform streams
switchMap, mergeMap, concatMap — Flatten observables
debounceTime, distinctUntilChanged — Rate limiting
takeUntil, take, first — Completion control
combineLatest, forkJoin, zip — Combine streams

Subjects: Subject, BehaviorSubject, ReplaySubject
📡

Signals (v16+)

Angular Signals are a new reactive primitive that synchronously track state changes, enabling fine-grained reactivity without Zone.js.

Signal API:
signal(value) — Create a writable signal
computed(() => expr) — Derived reactive value
effect(() => {}) — Side effects
.set(v), .update(fn), .mutate(fn) — Update signal

RxJS Interop: toSignal() and toObservable() bridge the gap between Signals and RxJS.
🔌

Directives

Classes that add behavior to DOM elements. Angular has three types: Component directives, Structural directives, and Attribute directives.

Built-in Structural: *ngIf, *ngFor, *ngSwitch, @if, @for, @switch
Built-in Attribute: ngClass, ngStyle, ngModel

Custom Directive:
@Directive({ selector: '[appHighlight]' })
Use HostListener for events and HostBinding for properties.
🧪

Pipes

Transform displayed values in templates. Pure pipes only execute when input changes; impure pipes run on every change detection cycle.

Built-in Pipes:
DatePipe — Format dates
CurrencyPipe — Format currency
DecimalPipe — Format numbers
UpperCasePipe / LowerCasePipe
AsyncPipe — Unwrap Observables/Promises
JsonPipe — Serialize to JSON

Custom Pipe: Implement PipeTransform interface and its transform() method.
📝

Forms

Angular provides two approaches to handling user input: Template-driven forms and Reactive forms, each with different trade-offs.

Template-driven: Simple, uses ngModel. Good for simple forms.

Reactive Forms:
FormControl — Single field
FormGroup — Group of controls
FormArray — Dynamic list of controls
FormBuilder — Factory helper
• Built-in validators: required, minLength, maxLength, pattern, email
• Custom validators as functions or classes

Change Detection

Angular's mechanism to sync the view with the model. Zone.js intercepts async ops and triggers detection; Signals offer a zoneless future.

Strategies:
Default — Check entire component tree
OnPush — Check only on @Input changes or observables emitting

Manual Control:
ChangeDetectorRef.detectChanges()
ChangeDetectorRef.markForCheck()
NgZone.runOutsideAngular()

Zoneless (experimental): provideExperimentalZonelessChangeDetection()
03 — Architecture

How Angular Works

Angular's layered architecture separates concerns cleanly from templates to services to the platform.

┌─────────────────────────────────────────────────────────────────┐ BROWSER / PLATFORM │ ┌───────────────────────────────────────────────────────────┐ │ │ │ AppModule / bootstrapApplication() │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ │ │ AppComponent (Root Component) │ │ │ │ │ │ ┌───────────────┐ ┌───────────────┐ │ │ │ │ │ │ │ FeatureModule │ │ SharedModule │ │ │ │ │ │ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ │ │ │ │ │ │ │Component │ │ │ │Directive │ │ │ │ │ │ │ │ │ │ Template │ │ │ │ Pipe │ │ │ │ │ │ │ │ │ │ Styles │ │ │ └───────────┘ │ │ │ │ │ │ │ │ └─────┬─────┘ │ └───────────────┘ │ │ │ │ │ │ └───────│───────┘ │ │ │ │ │ └──────────│──────────────────────────────────────────┘ │ │ │ │ │ injects via DI │ │ │ │ ┌──────────▼──────────────────────────────────────────┐ │ │ │ │ │ Services / Providers / Injector Tree │ │ │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ │ │ │ │ │ │ HttpClient│ │ Router │ │ Custom Services │ │ │ │ │ │ │ └──────────┘ └──────────┘ └──────────────────┘ │ │ │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ └───────────────────────────────────────────────────────────┘ │ │ Zone.js / Change Detection / Ivy Renderer / Angular Signals │ └─────────────────────────────────────────────────────────────────┘
04 — Code Examples

Angular in Practice

Real-world code patterns across components, services, routing, and more.

📄 user-profile.component.ts TypeScript
import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { UserService } from './user.service';
import { User } from './user.model';

@Component({
  selector: 'app-user-profile',
  standalone: true,
  imports: [CommonModule],
  template: `
    <div class="profile" *ngIf="user; else loading">
      <img [src]="user.avatar" [alt]="user.name" />
      <h2>{{ user.name }}</h2>
      <p>{{ user.email }}</p>
      <button (click)="onEdit()">Edit Profile</button>
    </div>
    <ng-template #loading>Loading...</ng-template>
  `,
  styleUrls: ['./user-profile.component.scss']
})
export class UserProfileComponent implements OnInit {
  @Input() userId!: string;
  @Output() editRequested = new EventEmitter<User>();

  user: User | null = null;

  constructor(private userService: UserService) {}

  ngOnInit(): void {
    this.userService
      .getUserById(this.userId)
      .subscribe(user => this.user = user);
  }

  onEdit(): void {
    if (this.user) this.editRequested.emit(this.user);
  }
}
📄 Modern Control Flow (v17+) Template
<!-- New @if / @for / @switch syntax (Angular 17+) -->
<div class="user-list">

  @if (users().length > 0) {
    <ul>
      @for (user of users(); track user.id) {
        <li>
          {{ user.name }} — {{ user.role }}
          @if (user.isAdmin) {
            <span class="badge">Admin</span>
          }
        </li>
      } @empty {
        <li>No users found</li>
      }
    </ul>
  } @else {
    <p>Loading users...</p>
  }

</div>

<!-- Deferrable Views (v17+) -->
@defer (on viewport) {
  <app-heavy-widget />
} @placeholder {
  <div class="skeleton"></div>
} @loading (minimum 300ms) {
  <app-spinner />
}
📄 user.service.ts TypeScript
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable, BehaviorSubject, throwError } from 'rxjs';
import { catchError, map, tap, retry } from 'rxjs/operators';
import { User } from './user.model';

@Injectable({
  providedIn: 'root' // Singleton at root level
})
export class UserService {
  private readonly API = 'https://api.example.com/users';
  private currentUser$ = new BehaviorSubject<User | null>(null);

  /** Public observable for current user */
  currentUser = this.currentUser$.asObservable();

  constructor(private http: HttpClient) {}

  getUsers(page = 1, limit = 10): Observable<User[]> {
    const params = new HttpParams()
      .set('page', page)
      .set('limit', limit);

    return this.http.get<{ data: User[] }>(this.API, { params }).pipe(
      map(res => res.data),
      retry(2),
      catchError(err => throwError(() => err))
    );
  }

  getUserById(id: string): Observable<User> {
    return this.http.get<User>(`${this.API}/${id}`).pipe(
      tap(user => this.currentUser$.next(user))
    );
  }

  updateUser(id: string, data: Partial<User>): Observable<User> {
    return this.http.patch<User>(`${this.API}/${id}`, data);
  }

  logout(): void {
    this.currentUser$.next(null);
  }
}
📄 app.routes.ts TypeScript
import { Routes } from '@angular/router';
import { authGuard } from './guards/auth.guard';
import { userResolver } from './resolvers/user.resolver';

export const routes: Routes = [
  {
    path: '',
    redirectTo: 'home',
    pathMatch: 'full'
  },
  {
    path: 'home',
    loadComponent: () =>
      import('./home/home.component')
        .then(m => m.HomeComponent)
  },
  {
    path: 'users',
    canActivate: [authGuard],        // Route guard
    loadChildren: () =>
      import('./users/users.routes')  // Lazy module
        .then(m => m.USER_ROUTES)
  },
  {
    path: 'profile/:id',
    loadComponent: () =>
      import('./profile/profile.component')
        .then(m => m.ProfileComponent),
    resolve: {
      user: userResolver              // Pre-fetch data
    }
  },
  {
    path: '**',
    loadComponent: () =>
      import('./not-found/not-found.component')
        .then(m => m.NotFoundComponent)
  }
];

// Functional guard (Angular 15+)
export const authGuard = () => {
  const auth = inject(AuthService);
  const router = inject(Router);
  return auth.isLoggedIn() || router.parseUrl('/login');
};
📄 registration.component.ts TypeScript
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators, AbstractControl } from '@angular/forms';
import { ReactiveFormsModule } from '@angular/forms';

@Component({
  selector: 'app-registration',
  standalone: true,
  imports: [ReactiveFormsModule],
  template: `
    <form [formGroup]="form" (ngSubmit)="onSubmit()">
      <input formControlName="email" placeholder="Email" />
      <div *ngIf="email?.invalid && email?.touched">
        <span *ngIf="email?.errors?.['required']">Email is required</span>
        <span *ngIf="email?.errors?.['email']">Invalid email</span>
      </div>

      <div formGroupName="passwords">
        <input formControlName="password" type="password" />
        <input formControlName="confirm" type="password" />
        <span *ngIf="passwords?.errors?.['mismatch']">Passwords must match</span>
      </div>

      <button type="submit" [disabled]="form.invalid">Register</button>
    </form>
  `
})
export class RegistrationComponent implements OnInit {
  form!: FormGroup;

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.form = this.fb.group({
      email: ['', [Validators.required, Validators.email]],
      passwords: this.fb.group({
        password: ['', [Validators.required, Validators.minLength(8)]],
        confirm:  ['', Validators.required]
      }, { validators: this.matchPasswords })
    });
  }

  matchPasswords(group: AbstractControl) {
    const pw  = group.get('password')?.value;
    const cf  = group.get('confirm')?.value;
    return pw === cf ? null : { mismatch: true };
  }

  get email() { return this.form.get('email'); }
  get passwords() { return this.form.get('passwords'); }

  onSubmit() {
    if (this.form.valid) console.log(this.form.value);
  }
}
📄 counter.component.ts (Signals) TypeScript
import { Component, signal, computed, effect } from '@angular/core';
import { toSignal, toObservable } from '@angular/core/rxjs-interop';

@Component({
  selector: 'app-counter',
  standalone: true,
  template: `
    <div>
      <h2>Count: {{ count() }}</h2>
      <h3>Doubled: {{ doubled() }}</h3>
      <p>Status: {{ status() }}</p>

      <button (click)="increment()">+</button>
      <button (click)="decrement()">−</button>
      <button (click)="reset()">Reset</button>
    </div>
  `
})
export class CounterComponent {
  // Writable signal
  count = signal(0);

  // Computed (derived) signal — updates automatically
  doubled = computed(() => this.count() * 2);

  status = computed(() => {
    const n = this.count();
    if (n > 10) return 'High';
    if (n < 0)  return 'Negative';
    return 'Normal';
  });

  // Effect — runs when signal values change
  logEffect = effect(() => {
    console.log(`Count changed to: ${this.count()}`);
  });

  increment() { this.count.update(n => n + 1); }
  decrement() { this.count.update(n => n - 1); }
  reset()     { this.count.set(0); }
}

// RxJS interop — convert signal ↔ observable
const obs$  = toObservable(count);   // Signal → Observable
const sig   = toSignal(someObs$);   // Observable → Signal
📄 highlight.directive.ts TypeScript
import { Directive, ElementRef, HostListener, Input, Renderer2 } from '@angular/core';

@Directive({
  selector: '[appHighlight]',
  standalone: true
})
export class HighlightDirective {
  @Input('appHighlight') highlightColor = 'yellow';
  @Input() defaultColor = 'transparent';

  constructor(
    private el: ElementRef,
    private renderer: Renderer2
  ) {}

  @HostListener('mouseenter')
  onMouseEnter() {
    this.highlight(this.highlightColor);
  }

  @HostListener('mouseleave')
  onMouseLeave() {
    this.highlight(this.defaultColor);
  }

  private highlight(color: string) {
    this.renderer.setStyle(
      this.el.nativeElement,
      'background-color',
      color
    );
  }
}

// Usage in template:
// <p appHighlight="cyan" defaultColor="lightgray">Hover me</p>
// <p [appHighlight]="dynamicColor">Dynamic color</p>
📄 truncate.pipe.ts TypeScript
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'truncate',
  standalone: true,
  pure: true  // Default: only re-runs when input changes
})
export class TruncatePipe implements PipeTransform {
  transform(
    value: string,
    limit = 100,
    trail = '...'
  ): string {
    if (!value) return '';
    if (value.length <= limit) return value;
    return value.substring(0, limit) + trail;
  }
}

// Built-in pipe examples:
// {{ today | date:'longDate' }}
// {{ price | currency:'USD':'symbol':'1.2-2' }}
// {{ text | truncate:50:'…' }}
// {{ userObs$ | async }}   ← async pipe auto-subscribes
// {{ items | slice:0:5 }}
// {{ num | number:'1.0-2' }}
// {{ value | uppercase }}
// {{ obj | json }}
// {{ text | i18nSelect: mapping }}
05 — Component Lifecycle

The Lifecycle Hooks

Angular manages each component's lifecycle from creation to destruction. These hooks let you tap in at key moments.

constructor()

Construction

Class instantiated, DI runs. Don't access @Input values here — they aren't set yet. Keep it lean: DI only.

ngOnChanges

Input Changes

Fires when any @Input property changes. Receives a SimpleChanges object with previous and current values. Runs before ngOnInit.

ngOnInit

Initialization

Runs once after the first ngOnChanges. Perfect for fetching data, initializing forms, and setting up subscriptions. Most common hook.

ngDoCheck

Custom Change Detection

Runs on every change detection cycle. Use sparingly — it fires frequently. Good for detecting changes Angular can't catch (deep object mutations).

ngAfterContentInit

Content Projected

Fires after Angular projects external content into the component via <ng-content>. @ContentChild/@ContentChildren are accessible here.

ngAfterContentChecked

Content Checked

Runs after every content change detection check. Avoid heavy logic here. Called after every ngDoCheck for projected content.

ngAfterViewInit

View Initialized

Fires after the component's view (and child views) are initialized. @ViewChild/@ViewChildren are now accessible. Good for DOM manipulation.

ngAfterViewChecked

View Checked

Runs after every view change detection. Be careful — modifying bound data here can trigger ExpressionChangedAfterChecked errors.

ngOnDestroy

Cleanup

Called before Angular destroys the component. Unsubscribe from Observables, clear timers, detach event listeners. Critical to prevent memory leaks.

● Component lifecycle ● Content projection ● View lifecycle ● Destruction
06 — Angular CLI

Command Line Power

The Angular CLI is an essential tool for initializing, developing, scaffolding, and maintaining Angular applications.

npm install -g @angular/cli
Install Angular CLI globally via npm
ng new my-app --standalone --routing
Create a new Angular app with routing and standalone components
ng serve --open
Start dev server and open in browser (hot reload on changes)
ng generate component features/user
Generate a new component (also: g c). Creates .ts, .html, .scss, .spec.ts
ng generate service core/auth
Generate a new injectable service with test spec
ng generate module features/admin --routing
Generate a feature module with its own routing module
ng generate guard guards/auth --functional
Generate a functional route guard (Angular 15+)
ng generate pipe shared/truncate
Generate a custom pipe with its test spec file
ng generate directive shared/highlight
Generate a custom attribute directive
ng generate interceptor core/auth
Generate an HTTP interceptor (functional style)
ng build --configuration production
Build for production: AOT, tree-shaking, minification, source maps
ng test --code-coverage
Run unit tests via Karma + Jasmine and generate coverage report
ng e2e
Run end-to-end tests (configure with Cypress or Playwright)
ng update @angular/core @angular/cli
Update Angular to the latest version with automatic migrations
ng add @angular/material
Add Angular Material component library with schematic setup
ng lint
Lint the project using ESLint (after adding @angular-eslint)
ng extract-i18n
Extract i18n messages from templates to XLIFF/XMB/JSON files
ng analytics on
Enable CLI usage analytics reporting to the Angular team
07 — The Great Divide

AngularJS vs Angular

Angular (v2+) is a complete rewrite of AngularJS (v1). They share a name but little else.

Feature AngularJS (v1) Angular (v2+)
LanguageJavaScriptTypeScript (primary)
ArchitectureMVC / MVVMComponent-based
Data BindingTwo-way (ng-model)One-way + explicit two-way [(ngModel)]
RenderingDigest cycle ($scope)Ivy renderer + Zone.js / Signals
DI SystemService-based, single injectorHierarchical injector tree
RoutingngRoute / ui-router@angular/router (built-in)
MobileNot optimizedMobile-first, PWA ready
Performance$watch overheadAOT compilation, tree-shaking
TestingJasmine + KarmaJasmine + Karma + Jest + Testing Library
CLINone officialAngular CLI (powerful)
Server-Side RenderingNot built-inAngular Universal / built-in SSR (v17+)
Lazy LoadingManual, complexNative, route-based
AnimationsCSS + ngAnimate@angular/animations (state machine)
FormsTemplate-driven onlyTemplate-driven + Reactive
InternationalizationManualBuilt-in i18n + Angular Localize
EOL StatusEnd of Life Dec 2021Actively maintained
08 — Key Features

What Makes Angular Powerful

Angular is an opinionated, batteries-included framework designed for large-scale enterprise applications.

🔷

TypeScript First

Built with and for TypeScript. Enjoy static typing, interfaces, generics, and advanced IDE support out of the box.

🌲

Tree Shaking (Ivy)

The Ivy compiler eliminates unused code, resulting in dramatically smaller bundle sizes for production builds.

AOT Compilation

Ahead-of-Time compilation converts HTML and TypeScript into efficient JavaScript during the build process, before the browser downloads it.

🧵

Lazy Loading

Load feature modules only when needed, drastically reducing initial bundle size and improving Time-to-Interactive.

🌐

Angular Universal (SSR)

Server-Side Rendering and Static Site Generation for improved SEO, performance, and social sharing previews.

🔒

Built-in Security

Angular sanitizes data by default, preventing XSS attacks. HttpClient includes XSRF/CSRF protection. Content Security Policy support.

Accessibility (a11y)

ARIA attributes, keyboard navigation, and the Angular CDK A11y package provide powerful accessibility primitives.

📱

Progressive Web Apps

Angular CLI provides first-class PWA support via @angular/pwa — adding service workers and a web manifest in one command.

🧪

Testability

Dependency injection and the TestBed utility make unit testing straightforward. Angular strongly encourages test-driven development.

🎨

Angular Material

Official Material Design component library with 50+ accessible, customizable UI components following the Material 3 spec.

🔁

RxJS Integration

Deep integration with Reactive Extensions for JavaScript enables powerful async patterns, event streams, and state management.

🏗️

Nx / Monorepo

Angular works beautifully with Nx for monorepo architectures, enabling code sharing across multiple apps and libraries.

🌍

i18n Built-in

Angular Localize provides compile-time i18n with support for XLIFF, XMB/XTB formats and ICU expressions for pluralization.

🔌

HTTP Interceptors

Functional interceptors (v15+) allow transforming requests/responses globally — perfect for auth tokens, logging, and caching.

📦

NgRx / State Management

The official NgRx library brings Redux-inspired state management with Signals integration for predictable, scalable data flow.

🤖

Angular DevTools

Chrome extension for profiling Angular applications, visualizing component trees, and debugging change detection performance.

09 — Test Your Knowledge

Angular Quiz

10 questions to see how well you know Angular. Click an option to answer.