Toolmingo
Guides20 min read

50 Angular Interview Questions (With Answers)

Top Angular interview questions with clear answers and code examples — covering components, directives, services, RxJS, signals, routing, performance, and testing.

Angular interviews test component architecture, dependency injection, RxJS, reactive patterns, and performance optimisation. This guide covers the 50 most common questions — with concise answers and code examples updated for Angular 17+.

Quick reference

Topic Most asked questions
Architecture Components, modules, standalone, change detection
Templates Directives, pipes, two-way binding, new control flow
Services & DI Dependency injection, providers, hierarchical injectors
RxJS & Signals Observables, subjects, signals, toSignal/toObservable
Routing Lazy loading, guards, resolvers, functional guards
Performance OnPush, trackBy, defer, preloading, SSR
Testing TestBed, ComponentFixture, MockMvc, harnesses

Architecture

1. What is Angular and how is it different from React?

Angular is a full framework from Google — it includes routing, HTTP client, forms, DI, testing utilities, and CLI out of the box. React is a UI library that requires assembling a stack from separate packages.

Angular React
Type Full framework UI library
Language TypeScript (required) JavaScript/TypeScript
Data binding Two-way (ngModel) One-way by default
State Signals + RxJS useState + context
Learning curve Steeper Gentler
Opinionation High Low

2. What is a component in Angular?

A component is the fundamental UI building block. It consists of:

  • Class — logic and data
  • Template — HTML view
  • Styles — scoped CSS
  • Metadata@Component decorator
@Component({
  selector: 'app-user',
  standalone: true,
  imports: [NgIf, DatePipe],
  template: `
    <div *ngIf="user">
      <h2>{{ user.name }}</h2>
      <p>Joined: {{ user.createdAt | date:'mediumDate' }}</p>
    </div>
  `,
})
export class UserComponent {
  @Input() user?: User;
}

3. What is the difference between standalone components and NgModules?

NgModules (traditional) group components, directives, and pipes into cohesive units and declare their imports/exports. Standalone components (Angular 14+, default from Angular 17) declare their own dependencies via the imports array — no NgModule needed.

// Standalone (modern, default in Angular 17)
@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, CommonModule],
  templateUrl: './app.component.html',
})
export class AppComponent {}

// NgModule (legacy style)
@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, RouterModule],
  bootstrap: [AppComponent],
})
export class AppModule {}

Angular 17+ bootstraps with bootstrapApplication(AppComponent, appConfig) instead of platformBrowserDynamic().bootstrapModule(AppModule).

4. What is change detection in Angular?

Change detection is the mechanism Angular uses to keep the view in sync with the model. Angular checks whether component data has changed and updates the DOM accordingly.

Two strategies:

Strategy Behaviour
Default Checks every component on every event/timer/async op
OnPush Checks only when: @Input() reference changes, an event originates in the component, an async pipe emits, or markForCheck() is called manually
@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  // ...
})
export class ProductCardComponent {
  @Input() product!: Product; // must pass new reference to trigger check
}

5. What is Angular's dependency injection system?

Angular has a hierarchical DI system. Injectors form a tree that mirrors the component tree. When a component requests a service, Angular walks up the injector tree until it finds a provider.

// Provided in root — singleton for the whole app
@Injectable({ providedIn: 'root' })
export class AuthService { ... }

// Provided at component level — new instance per component subtree
@Component({
  providers: [CartService], // isolated instance
})
export class CartComponent {
  constructor(private cart: CartService) {}
}

// Modern: inject() function (usable in constructors & initializers)
export class ProductComponent {
  private http = inject(HttpClient);
}

Templates & Directives

6. What are Angular directives and what are the three types?

Directives extend HTML behaviour. There are three types:

Type Purpose Example
Component Directive with a template <app-card>
Structural Changes DOM structure *ngIf, *ngFor, @if, @for
Attribute Changes appearance/behaviour [ngClass], [ngStyle], custom [appHighlight]
// Custom attribute directive
@Directive({ selector: '[appHighlight]', standalone: true })
export class HighlightDirective {
  @HostListener('mouseenter') onEnter() {
    this.el.nativeElement.style.backgroundColor = 'yellow';
  }
  @HostListener('mouseleave') onLeave() {
    this.el.nativeElement.style.backgroundColor = '';
  }
  constructor(private el: ElementRef) {}
}

7. What is the difference between *ngIf and @if (Angular 17)?

Angular 17 introduced a built-in control flow syntax (@if, @for, @switch) that replaces *ngIf / *ngFor / *ngSwitch. The new syntax is part of the template language — no import of NgIf or CommonModule needed.

<!-- Legacy -->
<div *ngIf="isLoggedIn; else loginBlock">Welcome</div>
<ng-template #loginBlock>Please log in</ng-template>

<!-- Angular 17+ built-in control flow -->
@if (isLoggedIn) {
  <div>Welcome</div>
} @else {
  <div>Please log in</div>
}

@for also requires a track expression (replaces trackBy):

@for (item of items; track item.id) {
  <li>{{ item.name }}</li>
} @empty {
  <li>No items</li>
}

8. What is two-way data binding and how does ngModel work?

Two-way binding keeps the view and the model in sync in both directions. [(ngModel)] is syntactic sugar for [ngModel] (property binding) + (ngModelChange) (event binding):

<!-- These are equivalent -->
<input [(ngModel)]="username" />
<input [ngModel]="username" (ngModelChange)="username = $event" />

ngModel requires FormsModule in the component's imports. For reactive forms, use formControlName with ReactiveFormsModule instead.

9. What is the difference between [class], [ngClass], and class?

<!-- Static class — always present -->
<div class="card">

<!-- Single dynamic class (expression must be truthy) -->
<div [class.active]="isActive">

<!-- Object/array binding for multiple classes -->
<div [ngClass]="{ active: isActive, disabled: isDisabled }">
<div [ngClass]="['card', isActive ? 'active' : '']">

<!-- Angular 17: same as [ngClass], no import needed -->
<div [class]="{ active: isActive }">

Prefer [class.foo] for single classes and [ngClass] / [class] for conditional sets.

10. What are Angular pipes and how do you create a custom pipe?

Pipes transform template values: {{ value | pipeName:arg1:arg2 }}.

Built-in pipes: date, currency, decimal, percent, uppercase, lowercase, titlecase, json, slice, async, keyvalue.

// Custom pipe: truncates a string
@Pipe({ name: 'truncate', standalone: true, pure: true })
export class TruncatePipe implements PipeTransform {
  transform(value: string, limit = 100, ellipsis = '…'): string {
    return value.length > limit ? value.slice(0, limit) + ellipsis : value;
  }
}

Pure vs impure pipes:

  • pure: true (default) — called only when input reference changes. Efficient.
  • pure: false — called on every change detection cycle. Use sparingly (e.g. async pipe is impure).

Services & Dependency Injection

11. What is providedIn: 'root' and when would you NOT use it?

providedIn: 'root' registers the service with the root injector, creating a singleton shared across the entire app and enabling tree-shaking (unused services are removed from the bundle).

Avoid it when you need:

  • Lazy-module-scoped singletons — use providedIn: SomeModule or provide in the lazy route config
  • Per-component instances — provide in @Component({ providers: [MyService] })
  • Multiple independent instances — provide at different component levels

12. What is the difference between @Injectable, @Component, @Directive, and @Pipe?

All are Angular decorators that add metadata:

Decorator Used on Makes class...
@Injectable Service class Injectable via DI
@Component Component class Component with template
@Directive Directive class DOM behaviour modifier
@Pipe Pipe class Template value transformer

@Component and @Directive implicitly mark the class as injectable.

13. How do you share data between sibling components?

Options, from simplest to most powerful:

  1. Lift state to a common parent — parent passes data via @Input(), listens with @Output()
  2. Shared service with a Subject/BehaviorSubject — both components inject the service
  3. Signals in a shared servicesignal() / computed() for fine-grained reactivity
  4. NgRx / Akita / Elf — for complex global state
// Shared service approach
@Injectable({ providedIn: 'root' })
export class CartService {
  private _count = signal(0);
  count = this._count.asReadonly();

  add() { this._count.update(n => n + 1); }
}

14. What is HttpClient and how do you handle errors?

HttpClient makes HTTP requests and returns Observables. Import provideHttpClient() in app.config.ts.

@Injectable({ providedIn: 'root' })
export class ApiService {
  private http = inject(HttpClient);

  getUser(id: number): Observable<User> {
    return this.http.get<User>(`/api/users/${id}`).pipe(
      retry({ count: 2, delay: 1000 }),
      catchError(err => {
        if (err.status === 404) return throwError(() => new Error('User not found'));
        return throwError(() => err);
      })
    );
  }
}

Use HttpInterceptor (or the newer HttpInterceptorFn) to add auth headers, log requests, or handle 401 globally.


RxJS

15. What is an Observable and how does it differ from a Promise?

Observable Promise
Values 0, 1, or many Exactly 1
Execution Lazy (starts on subscribe) Eager (starts immediately)
Cancellable Yes (unsubscribe) No
Operators Rich (map/filter/switchMap…) Limited (.then/.catch)
Sync or async Both Always async
// Promise — eager, one value
const p = fetch('/api/data').then(r => r.json()); // starts now

// Observable — lazy, can emit many
const o$ = this.http.get('/api/data'); // nothing happens yet
const sub = o$.subscribe(data => console.log(data)); // starts now
sub.unsubscribe(); // cancels the request

16. What is the difference between Subject, BehaviorSubject, ReplaySubject, and AsyncSubject?

Type Replays to new subscribers Initial value
Subject Nothing (only future values) None
BehaviorSubject Last value Required
ReplaySubject(n) Last n values None
AsyncSubject Last value, only on complete None

BehaviorSubject is the most common for state management (new subscribers always get the current value).

17. What is the difference between switchMap, mergeMap, concatMap, and exhaustMap?

All flatten a higher-order Observable (Observable of Observables). They differ in concurrency:

Operator Behaviour Use case
switchMap Cancels previous inner Observable when new outer value arrives Search autocomplete
mergeMap All inner Observables run in parallel Parallel HTTP requests
concatMap Queues inner Observables, runs sequentially File upload queue
exhaustMap Ignores new outer values while inner is running Login button (prevent double submit)
// Typeahead: cancel previous search on each keystroke
this.searchControl.valueChanges.pipe(
  debounceTime(300),
  distinctUntilChanged(),
  switchMap(term => this.api.search(term))
).subscribe(results => this.results = results);

18. How do you avoid memory leaks with subscriptions?

Options:

// 1. takeUntilDestroyed (Angular 16+, preferred)
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

export class MyComponent {
  constructor() {
    this.service.data$.pipe(takeUntilDestroyed()).subscribe(...);
  }
}

// 2. async pipe (auto-unsubscribes in template)
// template: {{ data$ | async }}

// 3. Manual unsubscribe
private destroy$ = new Subject<void>();
ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); }
this.data$.pipe(takeUntil(this.destroy$)).subscribe(...);

Avoid takeUntilDestroyed inside a callback — use it at component init level.

19. What are Angular Signals and when should you use them instead of RxJS?

Signals (Angular 16+, stable in Angular 17) are a reactive primitive for synchronous state. RxJS is better for async event streams.

// Signals
count = signal(0);
doubled = computed(() => this.count() * 2);

increment() { this.count.update(n => n + 1); }

// In template — no async pipe needed
// {{ count() }} {{ doubled() }}

Use signals when: managing component state, deriving values, replacing BehaviorSubject for simple state.

Use RxJS when: HTTP, WebSockets, complex async pipelines, combining multiple event sources.

Interop:

import { toSignal, toObservable } from '@angular/core/rxjs-interop';

// Observable → Signal
data = toSignal(this.http.get<Data>('/api/data'), { initialValue: null });

// Signal → Observable
count$ = toObservable(this.count);

20. What is combineLatest and when would you use it?

combineLatest emits whenever any input Observable emits, combining the latest value from each:

// Show a product with its reviews once both arrive
combineLatest([
  this.productService.getProduct(id),
  this.reviewService.getReviews(id),
]).subscribe(([product, reviews]) => {
  this.product = product;
  this.reviews = reviews;
});

Note: combineLatest waits until all sources have emitted at least once. Use forkJoin for one-shot HTTP requests that all complete.


Routing

21. How do you set up lazy loading in Angular?

Lazy loading defers module/component bundles until the route is first visited.

// app.routes.ts
export const routes: Routes = [
  { path: '', component: HomeComponent },
  {
    path: 'dashboard',
    loadComponent: () =>
      import('./dashboard/dashboard.component').then(m => m.DashboardComponent),
  },
  {
    path: 'admin',
    loadChildren: () =>
      import('./admin/admin.routes').then(m => m.adminRoutes),
  },
];

loadComponent (standalone) is preferred over loadChildren (module-based) in modern Angular.

22. What are route guards and what are the four types?

Guards control navigation. Angular 14+ supports functional guards (preferred) instead of class-based guards.

Guard Interface/Type Controls
canActivate CanActivateFn Whether route can be activated
canActivateChild CanActivateChildFn Whether child routes can be activated
canDeactivate CanDeactivateFn Whether user can leave a route
canMatch CanMatchFn Whether route definition can be matched
resolve ResolveFn Pre-fetch data before activating
// Functional auth guard (Angular 15+)
export const authGuard: CanActivateFn = (route, state) => {
  const auth = inject(AuthService);
  const router = inject(Router);
  return auth.isLoggedIn() ? true : router.createUrlTree(['/login']);
};

// Usage
{ path: 'profile', component: ProfileComponent, canActivate: [authGuard] }

23. What is the difference between ActivatedRoute and Router?

  • ActivatedRoute — provides information about the current route (params, query params, data, URL segments)
  • Router — used for programmatic navigation
export class ProductComponent {
  private route = inject(ActivatedRoute);
  private router = inject(Router);

  constructor() {
    // Read route param
    this.route.paramMap.subscribe(params => {
      this.productId = +params.get('id')!;
    });

    // Or as a signal (Angular 17+)
    // this.productId = this.route.snapshot.paramMap.get('id');
  }

  goBack() {
    this.router.navigate(['/products']);
  }
}

24. What is a route resolver and when should you use it?

A resolver pre-fetches data before a route is activated, so the component receives data immediately (no loading state needed in the component).

export const productResolver: ResolveFn<Product> = (route) => {
  const id = +route.paramMap.get('id')!;
  return inject(ProductService).getProduct(id);
};

// Route config
{ path: 'products/:id', component: ProductDetailComponent, resolve: { product: productResolver } }

// Component
export class ProductDetailComponent {
  product = inject(ActivatedRoute).snapshot.data['product'] as Product;
}

When to use: pages where showing an empty/loading skeleton is bad UX (e.g. print views, PDF exports). For most SPAs, handling the loading state in the component is simpler.

25. What is RouterLink vs router.navigate() vs router.navigateByUrl()?

Use case
[routerLink] Template-based navigation
router.navigate(['/path', param]) Programmatic navigation (relative, array-based)
router.navigateByUrl('/path/42') Programmatic navigation (absolute URL string)

router.navigate() is preferred for programmatic navigation because it supports relative paths and query params cleanly.


Forms

26. What is the difference between Template-Driven and Reactive forms?

Template-Driven Reactive
Setup FormsModule + ngModel ReactiveFormsModule + FormBuilder
Control In template In class (explicit)
Testing Requires DOM Unit-testable without DOM
Scalability Simple forms Complex/dynamic forms
Async validators Harder First-class
// Reactive form
export class SignupComponent {
  private fb = inject(FormBuilder);

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

  submit() {
    if (this.form.valid) console.log(this.form.value);
  }
}

27. How do you write a custom validator?

// Synchronous validator
function noSpaces(control: AbstractControl): ValidationErrors | null {
  return control.value?.includes(' ')
    ? { noSpaces: 'Value must not contain spaces' }
    : null;
}

// Async validator (e.g. check username availability)
function uniqueUsername(api: UserApi): AsyncValidatorFn {
  return (control: AbstractControl): Observable<ValidationErrors | null> =>
    control.value
      ? api.checkUsername(control.value).pipe(
          debounceTime(300),
          map(taken => (taken ? { usernameTaken: true } : null)),
          catchError(() => of(null))
        )
      : of(null);
}

// Usage
email: ['', [Validators.required, noSpaces], [uniqueUsername(this.userApi)]]

Performance

28. What is OnPush change detection and when should you use it?

With OnPush, Angular only runs change detection for a component when:

  1. An @Input() reference changes (not a mutation)
  2. An event is triggered inside the component tree
  3. An async pipe in the template emits a new value
  4. markForCheck() is called programmatically

Use OnPush for all "dumb" / presentational components that receive data via @Input(). It can dramatically reduce unnecessary DOM checks in large trees.

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `<div>{{ user.name }}</div>`,
})
export class UserCardComponent {
  @Input() user!: User; // must pass new object, not mutate existing
}

29. What is trackBy in @for / *ngFor and why does it matter?

Without trackBy, Angular destroys and recreates all DOM nodes when the array changes. trackBy tells Angular to identify items by a key so only changed nodes are updated.

// Old ngFor syntax
*ngFor="let item of items; trackBy: trackById"
trackById(index: number, item: Item) { return item.id; }

// New @for syntax — track is required
@for (item of items; track item.id) {
  <app-item [item]="item" />
}

30. What is @defer in Angular 17?

@defer lazy-loads a block of the template (including its components/directives) only when a trigger condition is met, without any route changes.

@defer (on viewport) {
  <app-heavy-chart [data]="chartData" />
} @placeholder {
  <div class="chart-placeholder"></div>
} @loading (minimum 300ms) {
  <app-spinner />
} @error {
  <p>Failed to load chart</p>
}

Trigger options: on idle, on viewport, on interaction, on hover, on immediate, on timer(500ms), when condition.

31. How does Angular's SSR (Server-Side Rendering) work?

Angular Universal / Angular SSR renders the app on the server and sends HTML to the browser. The browser hydrates the static HTML, making it interactive.

// app.config.server.ts
export const config: ApplicationConfig = {
  providers: [provideServerRendering()],
};

Benefits: better First Contentful Paint (FCP), improved SEO. Gotchas: avoid window/document/localStorage in shared code — check with isPlatformBrowser().


Advanced Concepts

32. What is ContentChild vs ViewChild?

  • @ViewChild — queries a child element/component in the component's own template
  • @ContentChild — queries content projected via <ng-content>
// ViewChild: references something in THIS template
@ViewChild('myInput') inputRef!: ElementRef;

// ContentChild: references something projected from the parent
@ContentChild(HighlightDirective) highlight?: HighlightDirective;

33. What is ng-content and how does content projection work?

<ng-content> lets a parent pass HTML into a component's template slot.

// card.component.html
<div class="card">
  <div class="card-header"><ng-content select="[slot=header]"></ng-content></div>
  <div class="card-body"><ng-content></ng-content></div>
</div>

// Parent usage
<app-card>
  <h2 slot="header">Title</h2>
  <p>Body content here</p>
</app-card>

34. What is HostListener and HostBinding?

@Directive({ selector: '[appHighlight]', standalone: true })
export class HighlightDirective {
  @HostBinding('style.background') bg = 'transparent';
  @HostBinding('class.active') isActive = false;

  @HostListener('click') onClick() {
    this.isActive = !this.isActive;
    this.bg = this.isActive ? 'yellow' : 'transparent';
  }
}

In Angular 17+, prefer host property in the decorator:

@Directive({
  selector: '[appHighlight]',
  host: {
    '(click)': 'onClick()',
    '[style.background]': 'bg',
  }
})

35. What is forwardRef and when do you need it?

forwardRef defers the reference to a class that hasn't been declared yet (used to fix circular dependency issues in DI or NG_VALUE_ACCESSOR):

// Custom form control implementing ControlValueAccessor
providers: [{
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => CustomInputComponent),
  multi: true,
}]

36. What is the Angular CDK and what does it provide?

The Component Dev Kit (CDK) provides primitives for building custom UI components:

  • Drag and drop (DragDropModule)
  • Overlay / portal for dynamic content
  • Accessibility (FocusTrap, A11yModule, LiveAnnouncer)
  • Scrolling (virtual scroll for large lists)
  • Table (CdkTable, basis for MatTable)
  • Text field auto-resize

Import from @angular/cdk/* separately from Angular Material.


Testing

37. What is TestBed and how do you set up a component test?

TestBed is Angular's testing environment. It configures and creates an Angular testing module.

describe('UserCardComponent', () => {
  let component: UserCardComponent;
  let fixture: ComponentFixture<UserCardComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [UserCardComponent], // standalone component
    }).compileComponents();

    fixture = TestBed.createComponent(UserCardComponent);
    component = fixture.componentInstance;
    component.user = { id: 1, name: 'Alice' };
    fixture.detectChanges();
  });

  it('displays the user name', () => {
    const el = fixture.nativeElement.querySelector('h2');
    expect(el.textContent).toContain('Alice');
  });
});

38. How do you mock a service in an Angular test?

// Option 1: provide a spy object
const authSpy = jasmine.createSpyObj('AuthService', ['isLoggedIn']);
authSpy.isLoggedIn.and.returnValue(true);

await TestBed.configureTestingModule({
  imports: [AppComponent],
  providers: [{ provide: AuthService, useValue: authSpy }],
}).compileComponents();

// Option 2: override provider after setup
TestBed.overrideProvider(AuthService, { useValue: authSpy });

39. What is fixture.detectChanges() and when do you call it?

detectChanges() triggers Angular's change detection cycle in the test, updating the DOM to reflect the current component state. Call it:

  • Once after createComponent to run initial lifecycle hooks (ngOnInit)
  • Again after changing @Input() values or component properties
  • After async operations complete (use fakeAsync + tick() or waitForAsync)
it('shows loading spinner while fetching', fakeAsync(() => {
  component.loading = true;
  fixture.detectChanges();
  expect(fixture.nativeElement.querySelector('app-spinner')).toBeTruthy();

  component.loading = false;
  fixture.detectChanges();
  expect(fixture.nativeElement.querySelector('app-spinner')).toBeNull();
}));

40. What is the async pipe and why is it preferred in templates?

The async pipe:

  1. Subscribes to an Observable or Promise
  2. Returns the latest value
  3. Auto-unsubscribes when the component is destroyed
<!-- Without async pipe — manual subscription, risk of memory leak -->
<div>{{ username }}</div>

<!-- With async pipe — no subscription management needed -->
<div>{{ username$ | async }}</div>

<!-- With null guard -->
@if (user$ | async; as user) {
  <div>{{ user.name }}</div>
}

Signals (Angular 16–17+)

41. What are the three core Signal primitives?

Primitive Description
signal(value) Writable reactive value
computed(() => expr) Derived value, recalculated lazily when deps change
effect(() => sideEffect) Runs when signals it reads change
export class CounterComponent {
  count = signal(0);
  doubled = computed(() => this.count() * 2);

  constructor() {
    effect(() => console.log('Count changed to', this.count()));
  }

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

42. What are input(), output(), and model() (Angular 17.1+)?

Angular 17.1 introduced signal-based component I/O to replace @Input(), @Output(), and [(ngModel)]:

export class RatingComponent {
  // Signal input (required variant)
  value = input.required<number>();

  // Optional input with default
  max = input(5);

  // Two-way binding (replaces @Input + @Output)
  rating = model(0);

  // Output event
  selected = output<number>();

  select(n: number) {
    this.rating.set(n);
    this.selected.emit(n);
  }
}
<!-- Parent -->
<app-rating [(rating)]="userRating" [max]="10" (selected)="onSelect($event)" />

Angular CLI & Build

43. What are the most important Angular CLI commands?

Command Purpose
ng new my-app Create new project
ng generate component foo Generate component (ng g c)
ng generate service auth Generate service (ng g s)
ng serve Dev server (HMR enabled)
ng build Production build
ng test Run unit tests (Karma/Jest)
ng e2e Run E2E tests
ng lint Run linter
ng update Update Angular and dependencies
ng add @angular/material Add Angular Material

44. What is the difference between ng build and ng build --configuration production?

ng build (dev) — no minification, with source maps.
ng build --configuration production — enables:

  • Tree shaking (removes unused code)
  • Minification and uglification
  • AOT compilation (Ahead-of-Time, default since Angular 9)
  • Bundle optimisation and code splitting

45. What is AOT (Ahead-of-Time) compilation?

AOT compiles Angular templates at build time instead of at runtime (JIT). Benefits:

  • Smaller bundles (compiler not shipped to browser)
  • Faster rendering (template already compiled)
  • Earlier template error detection
  • Better security (no eval() in the browser)

AOT is the default since Angular 9 and is always used in production builds.


Common Mistakes

Mistake Problem Fix
Mutating @Input() objects Parent state silently changes Emit new object via @Output()
Subscribing without unsubscribing Memory leaks Use async pipe, takeUntilDestroyed()
Using any in templates Loses type safety Type all inputs explicitly
Calling a function in template Runs on every CD cycle Use computed() signal or pure pipe
Forgetting trackBy / track in lists Full DOM re-creation Always add track item.id
*ngIf + *ngFor on same element Template error Wrap with <ng-container>
subscribe inside subscribe Pyramid of doom Use switchMap / combineLatest
Using document directly Breaks SSR Use DOCUMENT token or Renderer2

Angular vs React vs Vue

Angular React Vue
Type Full framework UI library Progressive framework
Language TypeScript JS/TS JS/TS
Reactivity Signals + RxJS useState/useEffect Signals (Vapor) + Composition API
DI Built-in hierarchical Manual / context Manual / provide-inject
Forms Template + Reactive Uncontrolled/libraries v-model
CLI ng (powerful) create-react-app/Vite create-vue
Bundle size (core) Large (~50 kB) Medium (~35 kB) Small (~22 kB)
Learning curve Steep Medium Gentle

FAQ

Q: Should I use NgModules or standalone components in 2024?
A: Standalone components are the default in Angular 17 and the recommended approach for all new projects. NgModules are still supported but considered legacy for new code.

Q: When should I use Signals vs RxJS?
A: Signals for synchronous component state and derived values. RxJS for async streams, HTTP, WebSockets, or complex multi-source event pipelines. Use toSignal() / toObservable() to bridge them.

Q: What is the difference between ngOnInit and the constructor?
A: The constructor runs first and should only set up DI (inject services). @Input() values are not yet available in the constructor. Use ngOnInit for initialisation logic that depends on inputs or that triggers side effects.

Q: How does Angular handle forms with deeply nested groups?
A: Use FormGroup nesting with FormBuilder.group(). Access nested controls with form.get('address.street') or form.get(['address', 'street']). Use FormArray for dynamic lists of controls.

Q: What is the difference between canActivate and canMatch?
A: canActivate blocks navigation to a matched route. canMatch controls whether the route definition is even considered during matching — useful when you have multiple routes at the same path that serve different user roles.

Q: How do you upgrade Angular to a new major version?
A: Run ng update @angular/core @angular/cli which applies schematics to automatically migrate breaking changes. Check the Angular Update Guide first — it lists all breaking changes and required manual steps for each version pair.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools