Angular Interview Questions 2026

Angular interviews tend to go deeper than most frontend frameworks, mainly because Angular itself is more opinionated and comes with more built-in machinery, dependency injection, RxJS, its own change detection system, than something like React leaves you to figure out yourself. That means the questions naturally go past "how do you render a list" and into "why is this component not re-rendering when I expected it to" or "why do I have two instances of a service I thought was a singleton."

This page works through Angular from components and data binding up through RxJS, dependency injection, routing, forms, and change detection, ending with the newer signal-based reactivity model that's changing a lot of these answers going forward.

Why Angular Interviews Go Deeper Than You'd Expect

Angular bundles in a lot of infrastructure that other frameworks leave to separate libraries, which means there's simply more surface area for an interviewer to probe. Angular questions are used to check:

  • Whether you understand Angular's own concepts (modules, DI, change detection) or you're just pattern-matching syntax from tutorials
  • Whether you know why RxJS shows up everywhere in Angular, not just how to chain a few operators
  • Whether you can reason about performance, especially change detection, which is a genuinely common source of real production bugs
  • Whether you're aware of where Angular is actually heading, standalone components and signals have meaningfully changed "the Angular way" in recent versions

Who This Page Is For

  • Frontend and full stack developers interviewing for roles that specifically use Angular
  • Developers coming from React or Vue who need to get comfortable with Angular's specific patterns
  • Anyone prepping for an enterprise frontend role, Angular remains extremely common in large, established codebases

Angular Interview Questions and Answers (2026)

Angular Fundamentals

1. What is Angular, and how is it actually different from a library like React? People call both "frameworks" but that's not quite right.

Angular is a complete, opinionated framework, it ships with routing, forms, HTTP handling, dependency injection, and a build system all built in and expected to be used together. React is genuinely just a library for building UI components, rendering and state management, and everything else, routing, forms, HTTP, is left to you to pick a separate library for. That's the real distinction people mean when they say Angular is a "framework" and React is a "library," Angular hands you a full toolbox with strong opinions about how the pieces fit together, React hands you one tool and lets you assemble the rest yourself.

2. What's the difference between AngularJS and Angular (2+)? Why did the whole thing get essentially rewritten from scratch?

AngularJS (version 1.x) was built around a fundamentally different architecture, two-way data binding through $scope, a JavaScript-based (not TypeScript) codebase, and a digest cycle for change detection that had real performance ceilings on large applications. Angular (2 and onward, often just called "Angular") is a complete rewrite in TypeScript, with a component-based architecture, a new dependency injection system, and a different, more efficient change detection model, it's not an upgrade path in the traditional sense, migrating from AngularJS to Angular is closer to migrating to an entirely different framework that happens to share a name and some philosophy.

3. What is the Angular CLI, and what does ng new actually set up for you?

The Angular CLI is a command-line tool for scaffolding, building, testing, and serving Angular applications without manually wiring together a build configuration yourself. ng new generates a complete, working project structure, TypeScript configuration, a base app module or standalone bootstrap setup, testing configuration (Karma/Jasmine by default), linting config, and a build pipeline already wired to bundle and optimize your app, it also offers to set up routing and your preferred stylesheet format interactively.

4. What's the difference between a component, a module, and a service at a conceptual level?

A component controls a piece of the UI, its template, styling, and the logic tied directly to that view. A service holds reusable logic or state that isn't tied to any specific view, API calls, shared business logic, data that multiple components need access to. A module (in the traditional NgModule-based architecture) is an organizational container, grouping related components, directives, pipes, and services together and declaring what's available for use within that group and what gets exposed to the rest of the app.

5. What is a standalone component, and how does it change the traditional NgModule-based architecture?

A standalone component declares its own dependencies directly (imports other components, directives, and pipes right in its own @Component decorator) instead of relying on being declared inside an NgModule that provides that context. This removes the need for NgModule entirely for a lot of applications, simplifying the mental model, fewer files to keep in sync, more explicit dependencies right where they're used, and newer Angular apps (and the CLI's default scaffolding) have shifted toward standalone components as the default approach rather than modules.

6. What's the difference between AOT and JIT compilation, and why does Angular default to AOT in production builds?

JIT (Just-In-Time) compilation compiles your Angular templates into executable JavaScript in the browser, at runtime, right before the app actually renders. AOT (Ahead-Of-Time) compilation does that same compilation step during the build process, before the app ever ships to a browser, so the browser just runs already-compiled code directly. AOT is the default for production because it means faster initial rendering (no compilation step happening in the user's browser), smaller bundle size (the template compiler itself doesn't need to ship to the browser), and it catches template errors at build time instead of at runtime in front of a real user.


Components, Templates and Data Binding

1. What are the four types of data binding in Angular, and what's the syntax for each?

Interpolation, {{ value }}, displays a component property's value as text in the template. Property binding, [property]="value", sets a DOM element or component property from your component's data. Event binding, (event)="handler()", calls a component method in response to a DOM event. Two-way binding, [(ngModel)]="value", combines property and event binding together, the value flows into the element and updates from the element flow back into the component automatically.

2. What's the difference between interpolation and property binding? They seem to do similar things.

Interpolation ({{ value }}) is specifically for rendering a value as text content inside an element or attribute. Property binding ([property]="value") sets an actual DOM property or a component's @Input(), not just text, which matters for things that aren't strings, like binding a boolean to disabled or an object to a child component's input, interpolation would just stringify it awkwardly, property binding passes the actual typed value through correctly.

<p>{{ username }}</p>
<button [disabled]="isSubmitting">Submit</button>

3. What is two-way data binding, and what's actually happening under the hood with [(ngModel)]?

[(ngModel)] is Angular's "banana in a box" syntax, and it's really just syntactic sugar combining property binding and event binding into one expression: [ngModel]="value" sets the input's value from the component, and (ngModelChange)="value = $event" listens for changes and writes the new value back to the component property. It's not some special separate mechanism, it's built entirely from the same one-way binding primitives Angular already has, just combined into a more convenient syntax.

4. What's the difference between @Input() and @Output(), and how does a child component actually notify a parent of something?

@Input() marks a property on a child component that a parent can bind data into, from parent to child. @Output() marks an EventEmitter property that a child component uses to emit events, which the parent listens to with event binding, from child to parent. A child never directly calls a method on its parent, it emits an event through its @Output(), and it's entirely up to the parent's template to decide whether (and how) to listen and react to it, keeping the coupling one-directional and explicit.

@Output() itemSelected = new EventEmitter<string>();

selectItem(id: string) {
  this.itemSelected.emit(id);
}

5. What is content projection (ng-content), and what's a real use case for it?

Content projection lets a parent component pass actual markup into a child component's template, rather than just data, the child declares an <ng-content> slot in its own template, and whatever HTML the parent puts between the child component's opening and closing tags gets rendered right there. A real use case is a reusable card or modal component, the card component handles the styling and layout, but the parent decides what actual content, text, buttons, other components, goes inside it, without the card component needing to know or care what that content is.

6. What's the difference between ViewChild and ContentChild?

@ViewChild gives you a reference to an element or child component that's defined directly in the current component's own template. @ContentChild gives you a reference to an element or component that was projected into the current component via <ng-content>, content that came from the parent, not something the component itself declared. The distinction matters because they're populated at different lifecycle points, and mixing them up (looking for a projected element with ViewChild, for example) is a common source of "why is this always undefined" bugs.


Directives and Pipes

1. What's the difference between a structural directive and an attribute directive, and how do you tell them apart in a template?

A structural directive changes the actual DOM structure, adding, removing, or repeating elements, and is identified by a leading asterisk in the template, *ngIf, *ngFor. An attribute directive changes the appearance or behavior of an existing element without altering the DOM structure around it, and it's used like a regular attribute binding, no asterisk, [ngClass], [ngStyle], or a custom directive like appHighlight.

2. What's actually happening under the hood when you use *ngIf or *ngFor? What does the asterisk syntax expand to?

The asterisk is shorthand for Angular's <ng-template> microsyntax, *ngIf="condition" desugars to wrapping the element in an <ng-template [ngIf]="condition">, which Angular uses as a reusable template that it conditionally instantiates (or destroys) into the DOM based on the directive's logic. This is worth knowing because it explains why elements removed by *ngIf are actually destroyed and recreated, not just hidden with CSS, unlike something like [hidden], which just toggles visibility while the element stays in the DOM.

3. What is a pipe, and what's the difference between a pure and an impure pipe?

A pipe transforms a value directly in the template for display, formatting a date, currency, or filtering a list, without you having to write that transformation logic in the component class. A pure pipe (the default) only re-runs its transform when its input reference actually changes, which is efficient but means it won't detect in-place mutations to an object or array, mutating an array's contents without creating a new array reference won't trigger a pure pipe to re-run. An impure pipe re-runs on every single change detection cycle regardless of whether the input actually changed, which is more "correct" for detecting mutations but comes with a real performance cost if used carelessly.

4. Why can a pipe that's not marked pure hurt performance if used carelessly?

Because Angular calls an impure pipe's transform method on every change detection run, potentially many times per second during animations or frequent user interaction, regardless of whether the actual input value changed at all. If that pipe does anything even moderately expensive, filtering a large array, formatting complex data, that expensive work now runs constantly instead of only when it actually needs to, which is exactly the kind of thing that shows up as a sluggish, janky UI under real use, even though it works fine with a small amount of test data.

5. How would you write a custom structural directive from scratch?

You'd implement a directive class that injects TemplateRef (a reference to the template it's attached to) and ViewContainerRef (the place in the DOM where you can insert or clear views), then use the directive's input setter to decide, based on your custom logic, whether to call viewContainer.createEmbeddedView(templateRef) to render it, or viewContainer.clear() to remove it, which is essentially the same underlying mechanism *ngIf itself uses internally.


Services and Dependency Injection

1. What is dependency injection, and why does Angular build it in as a core part of the framework instead of leaving it to a third-party library?

Dependency injection is a pattern where a class declares what it needs (its dependencies) through its constructor, and something external, the injector, is responsible for actually creating and providing those dependencies, rather than the class creating them itself. Angular builds it in natively because DI is used so pervasively throughout the framework itself, services, HTTP client, router, that having it as a first-class, built-in concept makes the whole framework more consistent and testable, you can easily swap in mock dependencies for testing without fighting against how the framework itself is wired.

2. What's the difference between providing a service in a module, in a component, and using providedIn: 'root'?

providedIn: 'root' (set directly on the @Injectable decorator) registers the service with the root injector, making it a true, app-wide singleton, and it also enables tree-shaking, if nothing actually injects the service, it won't even end up in your final bundle. Providing a service in a module's providers array registers it at that module's injector level. Providing it directly in a component's providers array creates a new instance of that service scoped specifically to that component (and its children), which is the intentional way to get a non-singleton, component-scoped instance when you actually want isolated state per component instance.

3. What does it mean for a service to be a singleton in Angular, and how can you accidentally end up with multiple instances of what you thought was a singleton?

A singleton means exactly one instance of that service exists and is shared by everything that injects it, which is the default and expected behavior for providedIn: 'root' services. You can accidentally break this by also listing that same service in a component's own providers array, which creates a brand new, separate instance scoped to that component's injector, shadowing the root instance for that component and its children, this is a genuinely common bug, "why isn't my shared state updating everywhere," usually traced back to a service being redundantly provided somewhere it shouldn't be.

4. What is a provider token, and why would you ever need an InjectionToken instead of just using a class as the token?

A provider token is what Angular's injector uses as the lookup key to know which dependency to provide, and normally that's just the class itself, constructor(private myService: MyService). An InjectionToken is needed when you want to inject something that isn't a class, a plain configuration object, a primitive value, or an interface (which doesn't exist at runtime in TypeScript and so can't be used as a DI token), InjectionToken gives you a unique, type-safe token you can use to register and inject that kind of value through the same DI system.

5. What's the difference between constructor injection and the newer inject() function?

Constructor injection is the traditional approach, dependencies are declared as constructor parameters and Angular's injector supplies them when the class is instantiated. The inject() function achieves the same result but can be called directly within a field initializer or a function body (like inside a standalone function-based guard or resolver) rather than requiring a class constructor at all, which is particularly useful now that Angular supports functional guards, resolvers, and interceptors that aren't classes and therefore have no constructor to inject through in the traditional way.


RxJS and Observables in Angular

1. What's the difference between an Observable and a Promise, and why does Angular lean so heavily on Observables over Promises?

A Promise represents a single future value and resolves exactly once, it can't be cancelled once started, and it's eager, it starts running as soon as it's created. An Observable can emit multiple values over time, supports cancellation (unsubscribing), and is lazy, it doesn't start doing anything until something actually subscribes to it. Angular leans on Observables because a huge amount of what Angular deals with is inherently a stream of values over time, not a single result, route parameter changes, form value changes, HTTP requests you might want to cancel mid-flight, and RxJS operators give you a powerful, composable way to transform and combine those streams.

2. What's the difference between switchMap, mergeMap, and concatMap, and when do you actually pick one over another?

switchMap cancels the previous inner observable whenever a new outer value arrives and switches entirely to the new one, ideal for something like a search-as-you-type feature, where you only care about the response to the latest keystroke and want to cancel any stale in-flight requests. mergeMap runs all inner observables concurrently without cancelling anything, fitting cases where you genuinely want every triggered request to complete independently, order doesn't matter. concatMap runs inner observables strictly one at a time, in order, waiting for each to complete before starting the next, useful when the order of operations genuinely matters, like a sequence of dependent API calls that must happen one after another.

searchTerm$
  .pipe(
    debounceTime(300),
    switchMap((term) => this.api.search(term))
  )
  .subscribe((results) => (this.results = results));

3. Why is unsubscribing from an Observable important, and what actually happens if you forget to?

If you subscribe to a long-lived observable (like one tied to a service that outlives a component, say listening to router events or a WebSocket) and never unsubscribe, that subscription keeps the callback, and everything it closes over, alive in memory even after the component that created it has been destroyed and removed from the DOM. This is a memory leak, and over time, in a long-running single-page application, accumulating enough of these leaked subscriptions can genuinely degrade performance or cause the app to slow down and consume increasing memory the longer a user stays on the page.

4. What's the difference between the async pipe and manually subscribing in a component? Why is the async pipe usually preferred?

Manually subscribing in a component's TypeScript code means you're responsible for calling unsubscribe() yourself, typically in ngOnDestroy, and forgetting to do so is exactly the memory leak scenario described above. The async pipe, used directly in the template ({{ data$ | async }}), subscribes to the observable automatically when the component initializes and automatically unsubscribes when the component is destroyed, no manual cleanup code required at all, which is exactly why it's the generally recommended default over manual subscription management whenever you're just displaying a stream's value in the template.

5. What's the difference between a Subject, a BehaviorSubject, and a ReplaySubject?

A plain Subject has no memory of past values, a new subscriber only receives values emitted after they subscribe, anything emitted before that is simply missed. A BehaviorSubject requires an initial value and always remembers and immediately emits its current (most recent) value to any new subscriber, useful for representing a piece of state that always has a "current value," like a logged-in user. A ReplaySubject can remember and replay a configurable number of past emissions (or all of them) to new subscribers, useful when a late subscriber genuinely needs the full history of recent events, not just the single most recent one.


Routing and Navigation

1. How does Angular's router decide which component to render for a given URL?

The router matches the current URL against an ordered list of route definitions you've configured, checking each route's path pattern in order until it finds a match (or a wildcard ** fallback), and then renders that route's associated component into the nearest <router-outlet> in the template. Because matching happens in order and stops at the first match, route ordering genuinely matters, a broad or wildcard route defined too early can accidentally shadow more specific routes defined after it.

2. What's the difference between a route guard and a resolver?

A guard controls whether navigation to a route is allowed to proceed at all, CanActivate for checking permission to enter a route, CanDeactivate for confirming it's safe to leave one (like warning about unsaved form changes), returning true, false, or a redirect to decide the navigation's fate. A resolver pre-fetches data before the route actually activates, so the component doesn't render in a loading state and then pop in data a moment later, the navigation itself waits until the resolver's data is ready, then the component receives it already available.

3. What is lazy loading in Angular routing, and why does it matter for a large application's initial load time?

Lazy loading means a route's associated code (and everything it depends on) is only downloaded and loaded into the browser when the user actually navigates to that route, instead of bundling every single feature of the application into one massive file that has to be downloaded before anything can render. For a large application with many distinct sections, this can dramatically shrink the initial bundle a user has to download before they see anything, since features they may never even visit in that session don't need to be loaded upfront at all.

4. What's the difference between routerLink and just using an <a href="..."> tag?

A plain <a href="..."> tag triggers a full browser page reload, re-downloading the entire application and losing any in-memory application state. routerLink intercepts the click and lets Angular's router handle the navigation internally, updating the URL and swapping the rendered component without a full page reload, preserving the single-page application experience and any state that shouldn't be lost, which is exactly why you almost always want routerLink for internal navigation within an Angular app, plain href defeats the entire point of being a single-page app.

5. How would you pass data between routes, route parameters vs query parameters vs router state?

Route parameters (/users/:id) are for identifying a specific resource as part of the URL path itself, they're required and part of the route's structure. Query parameters (?sort=name&page=2) are for optional, non-identifying data like filters or pagination state, they don't change which route matches. Router state lets you pass arbitrary data (even complex objects) directly during navigation without putting it in the URL at all, useful for passing data you don't want visible in the URL or that isn't meaningfully serializable, though it's worth remembering router state doesn't survive a page refresh the way URL-based parameters do, since it's not actually part of the URL.


Forms: Template-driven and Reactive

1. What's the actual difference between template-driven forms and reactive forms, and when would you pick one over the other?

Template-driven forms build the form structure implicitly, mostly in the HTML template using directives like ngModel, with Angular inferring and managing the underlying form model behind the scenes, which is simpler for small, straightforward forms. Reactive forms build the form model explicitly in the component's TypeScript code, using FormGroup and FormControl, giving you far more direct, testable control over validation, dynamic fields, and complex form logic. You'd reach for template-driven forms for genuinely simple cases, and reactive forms for anything with real complexity, dynamic validation, conditional fields, or forms you actually want to unit test properly.

2. What is a FormControl, a FormGroup, and a FormArray?

A FormControl tracks the value and validation state of a single form field. A FormGroup groups multiple FormControls (or nested FormGroups) together as one logical unit, aggregating their combined value and validity, matching a typical form with several fields. A FormArray is similar to a FormGroup but for a dynamic, variable-length list of controls, used when you don't know in advance how many of a given field there will be, like a form where a user can add or remove any number of phone numbers.

form = new FormGroup({
  name: new FormControl('', Validators.required),
  emails: new FormArray([new FormControl('')]),
});

3. How do you implement custom validation in a reactive form?

You write a validator function that takes an AbstractControl and returns either null (valid) or a validation error object (invalid), then attach it to a FormControl alongside or instead of Angular's built-in validators. For validation that depends on multiple fields together (not just one control in isolation), you'd write the same kind of function but attach it at the FormGroup level instead, since it needs access to sibling controls' values to actually evaluate.

function forbiddenNameValidator(
  control: AbstractControl
): ValidationErrors | null {
  return control.value === 'admin' ? { forbiddenName: true } : null;
}

4. What's the difference between a synchronous and an asynchronous validator?

A synchronous validator returns its result immediately, valid or invalid, right when it runs, used for checks you can evaluate instantly with data you already have, like a required field or a pattern match. An asynchronous validator returns an Observable or Promise instead, used when the validation genuinely requires waiting on something external, like checking with a server whether a username is already taken, and Angular marks the control as PENDING while it waits for that async validator to resolve.

5. How would you handle a form where one field's validity depends on another field's value?

You'd attach a validator at the FormGroup level rather than on an individual FormControl, since a group-level validator function receives the whole group and can read multiple sibling controls' values together, a classic example is a "confirm password" field, where its validity genuinely depends on comparing it against the separate password field's value, which an isolated, single-control validator has no access to.


Change Detection and Performance

1. What is change detection in Angular, and how does it actually decide when to re-render a component?

Change detection is the process Angular uses to check whether any data-bound values in your components have changed since the last check, and if so, update the corresponding parts of the DOM to match. By default, whenever any asynchronous event happens anywhere in the app, a click, an HTTP response, a timer, Angular runs a full change detection pass across the entire component tree, checking every component's bindings from top to bottom to see what actually needs updating.

2. What's the difference between the Default and OnPush change detection strategies?

With the Default strategy, Angular checks a component on every single change detection cycle, regardless of whether anything relevant to that component actually changed. With OnPush, Angular only checks a component when one of its @Input() references changes (a new object/array reference, not a mutation of the existing one), an event originates from within the component itself, or an observable bound via the async pipe emits a new value, which can dramatically cut down unnecessary checking in a large application if applied thoughtfully.

3. Why does using OnPush sometimes cause a component to not update when you expect it to, and how do you fix it?

The most common cause is mutating an object or array in place instead of creating a new reference, if you push a new item into an existing array and pass that same array reference into an OnPush component, Angular sees the same reference as before and doesn't detect a change, so the view doesn't update, even though the underlying data technically changed. The fix is either to always create new references when updating data intended for OnPush components (immutable update patterns, spreading into a new array/object), or to manually trigger change detection for that component using ChangeDetectorRef.markForCheck() when you know a relevant change happened that the strategy wouldn't automatically catch.

4. What is zone.js, and what role does it play in triggering change detection automatically?

Zone.js is a library Angular has traditionally relied on that patches (monkey-patches) browser and JavaScript async APIs, setTimeout, promises, DOM events, so Angular can automatically know whenever any of those async operations complete, without you having to manually tell Angular "something changed, please re-check." That's what makes Angular's automatic change detection possible without explicit calls scattered throughout your code, though it comes with some performance overhead, since it means change detection runs broadly on nearly every async event, whether or not that specific event actually affected anything visible.

5. What's Angular's newer signal-based reactivity model, and how does it differ from the traditional zone.js-based change detection?

Signals are a reactive primitive where a value is wrapped in a container that tracks exactly which parts of the template actually read it, so when a signal's value changes, Angular can update precisely and only the specific bindings that actually depend on that signal, instead of running a broad check across the whole component tree the way zone.js-triggered change detection does. This is a meaningfully more fine-grained and efficient model, and it's part of a broader shift where Angular is moving toward being able to eventually run without zone.js at all, relying on signals to know exactly what changed and where, rather than reactively re-checking everything after any async event.


Architecture, Testing and Production Practices

1. What's the difference between a smart (container) component and a dumb (presentational) component, and why structure an app that way?

A smart component handles logic, state management, and data fetching, typically talking to services and passing data down. A dumb (presentational) component just receives data via @Input() and emits events via @Output(), with no knowledge of where that data came from or what happens as a result of its events, it's purely about rendering. Structuring an app this way makes presentational components highly reusable and easy to test in isolation (no service dependencies to mock), while keeping the more complex, stateful logic concentrated in a smaller number of smart components instead of scattered everywhere.

2. What is TestBed, and how does it help you test an Angular component in isolation?

TestBed is Angular's testing utility for configuring and creating an isolated Angular testing module, similar in concept to an NgModule, that lets you declare the component under test, provide mock services or dependencies instead of real ones, and create a component instance with a real (test) Angular environment around it, giving you access to things like the component's actual DOM output through a ComponentFixture, so you can assert on rendered content, not just the component class's internal properties.

3. What's the difference between unit testing a component and doing an end-to-end test with something like Cypress or Playwright?

A unit test isolates a single component (or service) and verifies its behavior directly, typically running fast, in a simulated browser-like environment, and mocking out its dependencies so you're only testing that one unit's logic. An end-to-end (E2E) test runs the actual, fully built application in a real browser and simulates a genuine user journey across multiple pages and interactions, which is slower and more brittle but catches integration issues that isolated unit tests, by design, can't see, like whether the routing, styling, and actual rendered UI all genuinely work together correctly.

4. What is a barrel file (index.ts re-exports), and why do some Angular style guides actually advise against using them?

A barrel file re-exports multiple modules from a single index.ts, so consumers can import several things from one convenient path instead of many individual file paths. Some style guides advise caution with them because they can create circular dependency issues that are hard to trace, and they can hurt tree-shaking and build performance in large codebases, since bundlers sometimes struggle to fully eliminate unused code when everything funnels through a single re-export file, especially at scale.

5. How would you optimize the bundle size of a large Angular application?

Common approaches: lazy load feature routes so users only download code for the parts of the app they actually visit, use OnPush change detection and immutable data patterns to reduce unnecessary work (not directly bundle size, but a related performance lever), audit and remove unused dependencies, use the Angular CLI's built-in bundle analyzer to find unexpectedly large chunks, and make sure production builds are actually using AOT compilation and tree-shaking, which the CLI does by default but is worth explicitly verifying, especially in older or custom build configurations.



Struggling to Find a Job? Get Specific Batch Wise job Updates ✅ Check now

Join our WhatsApp Channel for more resources.