This lesson collects commonly asked Angular interview questions, from fundamentals through advanced topics like change detection and signals, with clear, concise answers you can use to prepare.
Pro Tip
When asked a conceptual question, briefly define the concept, then immediately walk through a tiny, concrete code example, this consistently reads as stronger, more practical understanding than a definition alone.
Extended Angular Interview Q&A
The following questions go deeper than the quick reference table above, with fuller
explanations for each answer.
1. What is the difference between a component and a directive?
Every component is technically a directive, an Angular class that can attach behavior to
the DOM, but a component always has a template of its own, while a plain directive
modifies an existing element without adding new markup. Use a component to render new
UI, and a directive to add behavior to markup that already exists.
2. What is the difference between constructor and ngOnInit?
The constructor is plain TypeScript and runs before Angular has finished setting up the
component's inputs. ngOnInit runs once, right after the first round of
input binding, making it the correct place for setup logic that depends on
@Input() values.
3. Explain Angular's change detection at a high level.
Angular listens for events (via Zone.js, which patches common async browser APIs) and,
when one occurs, walks the component tree checking each component's bindings for
changes, updating the DOM wherever a bound value actually changed. The
OnPush strategy and signals allow Angular to skip checking components that
can't have meaningfully changed, improving performance in large applications.
4. What problem does the OnPush strategy solve, and what does it require?
OnPush skips checking a component unless a specific trigger occurs: an
input changes by reference, an event originates within the component, a signal it
reads updates, or it's manually marked for check. It requires treating inputs as
immutable, mutating an object in place will not trigger a re-check, since the reference
never changed.
5. What is dependency injection, and why does Angular use it so heavily?
Dependency injection is a pattern where a class declares what it needs and an external
injector supplies matching instances, rather than the class creating its own
dependencies. Angular relies on it for testability (dependencies can be swapped for
mocks), for consistent object lifetimes (like singleton services), and for decoupling
classes from concrete implementations of what they depend on.
6. What's the difference between providedIn: 'root' and providing a service on a component?
providedIn: 'root' registers a tree-shakable, application-wide singleton,
every consumer shares one instance. Providing the same service in a component's own
providers array creates a separate instance scoped to that component and
its children, useful when you deliberately want isolated, non-shared state.
7. What is an Observable, and how does it differ from a Promise?
An Observable represents a stream of values over time and can emit zero, one, or many
values, and is cancellable via unsubscribe(). A Promise always resolves to
exactly one value (or rejects), starts executing immediately upon creation, and cannot
be cancelled. Observables also support a rich library of composable operators that
Promises lack natively.
8. When would you use switchMap versus mergeMap?
switchMap cancels the previous inner Observable when a new value arrives,
ideal for search-as-you-type, where only the latest request's result matters.
mergeMap runs all inner Observables concurrently without cancelling
earlier ones, appropriate when overlapping requests should all complete and you need
every result.
9. What are Angular signals, and how do they relate to computed() and effect()?
A signal is a reactive container for a value, read by calling it as a function and
updated with set()/update(). computed() derives
a new, read-only signal from other signals, recalculated only when a dependency
changes. effect() runs a side effect automatically in response to signal
changes, it should not be used to compute new state, that's what computed()
is for.
10. What is the difference between template-driven and reactive forms?
Template-driven forms build most of the form's structure in the HTML template using
ngModel, relying on FormsModule. Reactive forms build the
structure explicitly in TypeScript with FormGroup/FormControl
(via ReactiveFormsModule), which scales better to complex, dynamic, or
heavily-tested forms.
11. How do route guards work, and what's the difference between canActivate and canDeactivate?
Route guards are functions the router calls before allowing certain navigation.
canActivate controls whether a route can be entered (commonly used for
auth checks); canDeactivate controls whether the current route can be
left (commonly used for unsaved-changes confirmation). Both can return a boolean or a
UrlTree to redirect instead of simply blocking navigation.
12. What is lazy loading, and how do you implement it in modern Angular?
Lazy loading defers downloading a route's code until the user actually navigates to
it, reducing the initial bundle size. In modern Angular, this is done with
loadComponent (a single standalone component) or
loadChildren (a whole feature's routes) using a dynamic
import() inside the route configuration.
13. What is the purpose of HTTP interceptors?
Interceptors let you inspect and modify every outgoing request and incoming response
passing through HttpClient, useful for cross-cutting concerns like
attaching an auth token, logging, or handling specific error status codes globally,
without repeating that logic in every service. Modern Angular uses functional
interceptors registered with provideHttpClient(withInterceptors([...])).
14. When would you introduce NgRx instead of relying on services with signals?
NgRx is worth its added structure and boilerplate once an application's state is
genuinely complex, driven by many different sources, and needs strict traceability or
time-travel debugging. For small to medium apps, a well-designed singleton service
exposing signals is usually sufficient and far simpler to maintain.
15. How would you improve the performance of a large list rendered with @for?
First, ensure a proper track expression (usually a unique id) so Angular
can efficiently reconcile changes instead of recreating DOM nodes unnecessarily. For
very large lists, use the Component Dev Kit's virtual scrolling
(CdkVirtualScrollViewport) to render only the currently visible items.
Combining this with the OnPush strategy (or signal-based reactivity) on
list-item components further reduces unnecessary checks.