25 Angular Intermediate Interview Questions & Answers (Updated for Angular 17–18)
1. What are standalone components and when should you use them?
Standalone components (introduced and stabilized in recent Angular releases) allow components, directives, and pipes to be declared without NgModules; they declare their own dependencies via the standalone: true flag and import array, which simplifies app structure, reduces boilerplate, and makes lazy-loading and micro-frontends easier — prefer standalone components for new features and greenfield apps while incrementally migrating module-based code when beneficial.
2. What are Angular Signals and how do they differ from Observables?
Signals are a reactive primitive that represent mutable reactive values with synchronous read access; they enable fine-grained reactivity and change tracking at the usage site (component templates or functions) and are designed for high-performance local reactivity, whereas Observables (RxJS) represent asynchronous streams over time and are better for event/data streams, composition, and async operations — use signals for local state and UI reactivity, and Observables for async data flows and inter-component streams, combining both where appropriate.
3. What is the inject() function and how does it compare to constructor DI?
inject() is a compile-time-friendly helper that retrieves a dependency from the current injector (useful in functions, providers, and standalone contexts), allowing dependency resolution outside constructors; it complements traditional constructor injection by enabling DI in places like factory functions, standalone setup code, and module-level providers — use inject() when you need DI in non-class contexts or to simplify provider factories.
4. Explain Angular change detection and practical tips for performance.
Angular's change detection inspects components and updates views when model data changes; by default it runs broadly across component trees, but you can improve performance with ChangeDetectionStrategy.OnPush, immutable patterns, using Signals, the async pipe, manual ChangeDetectorRef control, trackBy in *ngFor, and avoiding heavy work inside template expressions; also prefer OnPush or granular reactive approaches for large lists and high-frequency updates to reduce unnecessary checks.
5. How do you prevent memory leaks in Angular applications?
Prevent leaks by unsubscribing from Observables (use async pipe in templates), applying operators like takeUntil with a destroy notifier, calling Subscription.unsubscribe() for imperative subscriptions, using take/first for one-time streams, cleaning DOM listeners in ngOnDestroy, and carefully managing long-lived Subjects or service-level streams; adopt patterns (e.g., destroy$) consistently across components.
6. Describe Signals + computed + effect — how would you use them together?
Signals hold reactive state, computed derives values from signals and recalculates when dependencies change, and effect runs side-effects on signal changes; together they replace many common patterns: store local state in signals, compute derived data with computed() (pure and memoized), and perform non-pure actions (HTTP calls, logging, DOM interactions) in effect(), keeping UI reactive and minimizing full-tree change detection.
7. How do standalone directives and pipes work?
Standalone directives and pipes mirror standalone components: they are declared with standalone: true, can be imported directly into component imports, and remove the need to bundle them into NgModules, which simplifies composition and sharing across features — use them to build reusable behavior or formatting that can be consumed by standalone components and modules alike.
8. Explain Hydration / SSR basics and when to use hydration.
Server-side rendering (SSR) renders HTML on the server for SEO and first-paint performance; hydration reuses server-rendered HTML on the client and attaches Angular runtime to make it interactive, reducing re-rendering and speeding time-to-interactive — use SSR/hydration for content-heavy sites, SEO-critical pages, or initial load optimizations, and be mindful of transfer-state and avoiding non-deterministic server/client rendering differences.
9. What is the Angular control-flow syntax (standalone control flow directives)?
Angular introduced improved control-flow directives to simplify templates (e.g., *ngIf, *ngFor) along with structural directive enhancements and typed contexts; newer control-flow syntax and template improvements focus on readability and performance, but the core idea remains: structural directives transform template DOM — write clear templates, use as and to reduce repetition, and prefer trackBy for performance.
10. How do you decide between Signals and NgRx for state management?
Signals are great for local and fine-grained UI state, simple global state, and performance-centric reactivity; NgRx (or other Redux-like libs) provides structured patterns (actions, reducers, effects) for large-scale apps requiring time-travel debugging, strict immutability, complex async workflows, and clear separation; choose Signals for simpler, high-performance state and NgRx for enterprise-level predictable state flows and tooling needs, or combine both (signals as local caches with NgRx for app-wide orchestration).
11. What is Zone.js / NgZone and when might you run code outside Angular's zone?
Zone.js intercepts async operations to trigger Angular change detection; NgZone provides control to run code outside Angular's zone (via runOutsideAngular) to avoid triggering change detection for non-UI work (e.g., high-frequency events, third-party libraries), and then use zone.run() to re-enter Angular when you need to update the view.
12. Describe dependency injection scopes and provider strategies (providedIn, module, component).
Providers can be application-wide with @Injectable({providedIn: 'root'}) (singletons), module-level via module providers, or component-level via component providers (creates new instance per component subtree); choose root for shared cross-app services, module for encapsulated feature instances, and component providers for isolated state (e.g., wizard steps) to control lifetime and instance boundaries.
13. How do HTTP Interceptors work and common use-cases?
HTTP interceptors implement HttpInterceptor and allow global request/response transformation: add auth tokens, refresh expired tokens, handle errors, log requests, or mock responses; chain interceptors in provider order and always return an Observableintercept() so the HTTP pipeline remains consistent.
14. What are Route Resolvers and when should you use them?
Resolvers fetch data before route activation so the component receives required data on initialization, preventing loader flicker and centralizing fetch logic; use resolvers for data dependencies that must be present before rendering (e.g., editing forms), but avoid heavy processing to keep navigation snappy — alternatives include fetching inside components or using route-level loading UX.
15. How to implement authentication guards (CanActivate / CanLoad) effectively?
Implement guards by returning boolean/Observable/Promise that checks auth state, optionally triggers login flows, and refreshes tokens; use CanLoad to prevent lazy-module download for unauthorized users, and CanActivate to stop navigation after download; ensure guards are fast, avoid heavy sync work, and handle asynchronous token refresh with care to avoid blocking UI unnecessarily.
16. Explain Reactive Forms — dynamic controls, custom validators, and performance tips.
Reactive Forms use explicit FormControl/FormGroup/FormArray APIs enabling dynamic control creation, complex sync/async validators, and easier unit testing; create/remove controls programmatically, implement custom validators as functions returning validation maps, and optimize performance by leveraging updateOn:'blur' or debouncing valueChanges, avoiding heavy computations in valueChanges subscriptions, and using OnPush change detection where appropriate.
17. What are Pipes and when to use pure vs impure pipes?
Pipes transform displayed values; pure pipes run only when input references change (fast and cacheable) and are preferred for most cases, while impure pipes run on every change detection cycle and should be used sparingly for non-deterministic transformations (e.g., date ranges, dynamic lists) due to performance cost — implement pure pipes for formatting and caching.
18. How do you test components and services with TestBed?
Use TestBed to configure a testing module that declares components and provides services, then create component fixtures to access component instance, detect changes, and assert DOM; mock dependencies using providers or spies, test services with isolated TestBed configs, and prefer shallow unit tests for logic plus integration tests for template bindings and interactions.
19. What is Ahead-of-Time (AOT) compilation and why prefer it?
AOT compiles templates into JavaScript during build time (not runtime), producing smaller bundles, faster startup, and earlier template error detection; prefer AOT for production builds to improve performance and catch template issues at build time.
20. How does trackBy improve ngFor performance?
trackBy provides a unique identifier for list items so Angular reuses DOM nodes when the array changes (instead of re-rendering all items), greatly improving performance for long lists or frequent updates — implement trackBy returning an item id or unique key to minimize DOM churn.
21. Explain HttpClient best practices (error handling, caching, optimistic updates).
Use HttpClient for typed API calls, centralize API logic in services, handle errors via catchError, implement caching with shareReplay or a caching layer, employ optimistic updates for responsive UIs (update UI immediately, revert on failure), and secure calls with interceptors for auth tokens and global error handling.
22. What is Ivy and how does it affect development or debugging?
Ivy is Angular's compilation and rendering engine that produces smaller bundles, faster builds, improved type-checking, and easier debugging through more meaningful stack traces; Ivy enables runtime instructions that make incremental compilation and local optimizations simpler, and developers should be familiar with its output for diagnosing template/runtime issues.
23. How to approach performance profiling and common optimizations in Angular apps?
Profile with Chrome DevTools, Lighthouse, and Angular DevTools to measure TTI and change detection cost; optimize by using OnPush, trackBy, memoization (computed signals), lazy loading, bundle splitting, AOT, defer non-critical work with requestIdleCallback, remove heavy synchronous tasks from templates, and reduce polyfills where safe.
24. How would you migrate a large NgModule-based app to standalone components incrementally?
Migrate gradually: start by converting isolated presentational components to standalone, update their imports, then create standalone feature components and routes using loadComponent or lazy-loaded standalone modules; keep compatibility by using imports arrays to pull in existing modules where needed, validate DI and providers, and apply thorough testing to ensure behavior remains consistent during the migration.
25. What are practical debugging techniques for template errors and change-detection bugs?
Use Angular DevTools to inspect component trees and change detection timings, enable strict templates to catch type issues, add console logs or breakpoints in component lifecycle hooks, simplify templates to isolate failing expressions, use OnPush temporarily to find unexpected updates, and write focused unit tests for template-bound logic to reproduce and fix issues quickly.