Angular Interview Questions
Prepare for Angular interviews at all levels — from junior to senior/architect roles. These are the most frequently asked questions, with concise but complete answers.
Fundamentals
Q: What is Angular and how does it differ from AngularJS?
Angular (v2+) is a complete rewrite of AngularJS. Key differences:
- Angular is built with TypeScript; AngularJS used JavaScript
- Angular uses a component-based architecture; AngularJS used controllers and scope
- Angular has unidirectional data flow; AngularJS used two-way binding with $scope
- Angular is mobile-first and significantly faster with ahead-of-time compilation
- AngularJS uses dependency injection via strings; Angular uses TypeScript types
Q: What is a Component in Angular?
// A Component is the basic building block of Angular apps.
// It controls a portion of the UI (a view) and consists of:
// 1. TypeScript class (logic)
// 2. HTML template (view)
// 3. CSS styles (styling)
// 4. Metadata via @Component decorator
@Component({
standalone: true,
selector: 'app-example', // How to use it in HTML
template: '<h1>{{ title }}</h1>',
styles: ['h1 { color: blue; }']
})
export class ExampleComponent {
title = 'Hello Angular';
}Q: What is the difference between a Component and a Directive?
Feature | Component | Directive |
|---|---|---|
Template | Yes — has its own template | No template |
Selector | Usually element: app-hero | Usually attribute: [appHighlight] |
Purpose | Create UI building blocks | Add behavior to existing elements |
View encapsulation | Yes | No |
Examples | AppComponent, UserCard | ngClass, ngIf, appTooltip |
Data Binding
Q: What are the types of data binding in Angular?
<!-- 1. Interpolation — one-way, component → DOM -->
<p>{{ title }}</p>
<!-- 2. Property binding — one-way, component → DOM -->
<input [value]="username" />
<button [disabled]="isLoading" />
<!-- 3. Event binding — one-way, DOM → component -->
<button (click)="onClick()">Click</button>
<!-- 4. Two-way binding — both directions -->
<input [(ngModel)]="username" />
<!-- [(ngModel)] is syntactic sugar for [ngModel]="val" (ngModelChange)="val=$event" -->Q: What is the difference between [value] and [(value)]?
[value]— property binding: data flows one-way from component to DOM[(value)]— two-way binding ("banana in a box"): data flows both ways. It's shorthand for[value]="x" (valueChange)="x = $event"
Services and Dependency Injection
Q: What is Dependency Injection (DI) in Angular?
DI is a design pattern where a class receives its dependencies from an external source rather than creating them itself. Angular's DI system maintains a hierarchy of injectors — root, module-level, and component-level.
When you inject(UserService), Angular traverses the injector tree upward until it finds a provider.
Q: What is the difference between providedIn: 'root' and providing in a component?
// providedIn: 'root' — single singleton instance for the entire app
@Injectable({ providedIn: 'root' })
export class GlobalService {}
// Provided in a component — new instance created per component tree
@Component({
providers: [LocalService] // Each instance of this component gets its own service instance
})
export class MyComponent {}Q: What is an Injection Token?
Injection tokens provide a way to inject values that aren't classes (strings, objects, functions):
export const API_URL = new InjectionToken<string>('API_URL');
// Register
providers: [{ provide: API_URL, useValue: 'https://api.example.com' }]
// Inject
const apiUrl = inject(API_URL);Change Detection
Q: How does Angular's change detection work?
Angular uses Zone.js to intercept asynchronous browser events (click, setTimeout, HTTP). After each event, Angular runs change detection — traversing the component tree top-down and checking if any template bindings have changed. If they have, it updates the DOM.
With OnPush strategy, a component is only checked when:
- An input reference changes
- An event fires within the component
markForCheck()ordetectChanges()is called explicitly- An Observable used with
asyncpipe emits
Q: What are Angular Signals and how do they improve performance?
// Signals provide fine-grained reactivity
// Only the specific DOM nodes reading a signal update when it changes
const count = signal(0);
const doubled = computed(() => count() * 2);
// effect() tracks which signals it reads and re-runs when they change
effect(() => console.log('count is', count()));
// In a component — only the {{count()}} binding updates, not the whole component
@Component({
template: `<p>{{ count() }}</p><p>{{ otherData }}</p>`,
})
export class SigComponent {
count = signal(0);
otherData = 'unchanged'; // Not re-rendered when count changes
}Routing
Q: What is lazy loading in Angular and why is it important?
Lazy loading defers loading a feature's JavaScript bundle until the user navigates to that route. This reduces the initial bundle size, improving load time and Time to Interactive.
// Without lazy loading — admin bundle loaded even if user never visits /admin
{ path: 'admin', component: AdminComponent }
// With lazy loading — admin bundle downloaded only on /admin navigation
{
path: 'admin',
loadComponent: () => import('./admin/admin.component').then(m => m.AdminComponent)
}Q: What are Route Guards?
Route Guards control navigation. They run before a route is activated and can allow or block navigation:
CanActivate— can the user enter this route?CanDeactivate— can the user leave this route (unsaved changes)?CanMatch— should this route even be considered?Resolve— pre-fetch data before activating the route
RxJS
Q: What is the difference between Subject, BehaviorSubject, and ReplaySubject?
Type | Initial Value | Late Subscriber Gets | Common Use |
|---|---|---|---|
Subject | None | Only future emissions | Events, one-time notifications |
BehaviorSubject | Required | Last emitted value | Current state (user, theme) |
ReplaySubject(n) | None | Last n emissions | Cache N recent values |
AsyncSubject | None | Only the last value on complete | Async operations that complete |
Q: What is the difference between switchMap, mergeMap, concatMap, and exhaustMap?
Operator | Behavior | Best For |
|---|---|---|
switchMap | Cancels previous inner observable | Search autocomplete, latest-wins |
mergeMap | Runs all in parallel | Independent HTTP requests |
concatMap | Queues — waits for each to complete | Sequential operations, file uploads |
exhaustMap | Ignores new while previous runs | Login button — prevent double submit |
Forms
Q: What is the difference between Template-driven and Reactive forms?
Feature | Template-driven | Reactive |
|---|---|---|
Form logic location | In the HTML template | In the component class |
Validation | HTML attributes (required, email) | Validators.required, custom validators |
Dynamic forms | Difficult | Easy with FormArray |
Unit testing | Requires DOM | No DOM needed — pure class |
Complex forms | Gets messy quickly | Scales well |
Best for | Simple forms | Complex, dynamic forms |
Q: How do you create a custom validator?
// Synchronous custom validator
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
export function noSpacesValidator(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const hasSpace = (control.value as string)?.includes(' ');
return hasSpace ? { noSpaces: { value: control.value } } : null;
};
}
// Usage
new FormControl('', [Validators.required, noSpacesValidator()])
// Async validator
export function usernameAvailableValidator(userService: UserService): AsyncValidatorFn {
return (control: AbstractControl): Observable<ValidationErrors | null> => {
return userService.checkUsername(control.value).pipe(
map((available) => available ? null : { usernameTaken: true }),
catchError(() => of(null)),
);
};
}Advanced Topics
Q: What is View Encapsulation in Angular?
Mode | Behavior |
|---|---|
Emulated (default) | CSS scoped to component via attribute selectors — styles don't leak |
None | Global CSS — styles affect the entire document |
ShadowDom | Native browser Shadow DOM — true encapsulation |
Q: What is the difference between ngOnInit and the constructor?
- Constructor — called by JavaScript when the class is instantiated. At this point Angular's DI has injected dependencies, but inputs are not yet set. Avoid logic here, only use for injection.
- ngOnInit — called by Angular after the first
ngOnChanges. Input properties are available. Put initialization logic (API calls, etc.) here.
Q: What is Content Projection?
Content projection lets a component accept external HTML content and render it inside its template
using <ng-content>:
<!-- 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> <!-- Default slot -->
</div>
</div>
<!-- Usage -->
<app-card>
<h2 slot="header">Card Title</h2>
<p>Card body content here</p>
</app-card>Q: What is the async pipe and what problem does it solve?
The async pipe subscribes to an Observable or Promise and returns the latest value.
When the component is destroyed, it automatically unsubscribes — preventing memory leaks.
It also calls markForCheck() when a new value arrives, making it work seamlessly with OnPush.
Q: What is AOT compilation?
Ahead-of-Time (AOT) compilation compiles Angular templates to JavaScript at build time rather than in the browser at runtime. Benefits:
- Faster rendering — no need to compile in the browser
- Smaller payload — Angular compiler not shipped to client
- Early template error detection — type errors caught during build
- Better security — no eval() of template strings at runtime
Angular uses AOT by default since v9 (Ivy).
Signals-Specific Questions
Q: What is the difference between signal() and BehaviorSubject?
Feature | signal() | BehaviorSubject |
|---|---|---|
Read value | count() — call as function | subject.value (synchronous) |
Subscribe | effect() or computed() | .subscribe() |
Angular template | Native — no pipe needed | Needs | async pipe |
Glitch-free | Yes — computed are lazy | No — intermediate states possible |
Zone.js required | No | No, but CD integration harder |
Best for | Component/service state in Angular 16+ | Stream-based state, interop |
Scenario-Based Questions
Q: How would you share data between sibling components?
Three approaches:
- Parent component — pass data down to both via
@Input()and listen for@Output()events - Shared service — inject a shared service with a Signal or BehaviorSubject into both
- State management — use NgRx or a signal store for complex shared state
Q: How do you prevent memory leaks when subscribing to Observables?
// Option 1: async pipe (preferred in templates)
// No unsubscribe needed — async pipe handles it
// Option 2: takeUntilDestroyed (Angular 16+, cleanest for class subscriptions)
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
constructor() {
this.data$.pipe(takeUntilDestroyed()).subscribe(handler);
}
// Option 3: Manual unsubscribe
private destroy$ = new Subject<void>();
ngOnInit() {
this.data$.pipe(takeUntil(this.destroy$)).subscribe(handler);
}
ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); }