Angular Interview Questions
Angular is one of the most common front-end framework topics in web developer interviews, and the questions repeat far more than candidates expect. These are the ones interviewers actually ask, grouped by theme and tagged by experience level.
118 questions with concise, interview-ready answers.
Contents
Angular Fundamentals
What is Angular and how does it differ from AngularJS?
FresherAngular (version 2 and above) is a TypeScript-based, component-driven front-end framework for building single-page applications, while AngularJS (1.x) was a JavaScript framework based on controllers and $scope. Angular introduced a component architecture, a hierarchical dependency injection system, RxJS observables, and ahead-of-time compilation. It is a complete rewrite, not an upgrade, and is generally faster and more maintainable than AngularJS.
What are decorators in Angular?
FresherDecorators are TypeScript functions that attach metadata to a class, property, method, or parameter, telling Angular how to process it. Common class decorators include @Component, @Directive, @Pipe, @NgModule, and @Injectable, while property decorators include @Input and @Output. They are what make Angular's declarative, metadata-driven architecture possible.
Why is Angular called a framework rather than a library?
FresherA library is code you call; a framework is code that calls you. Angular ships an opinionated set of the pieces an application needs — routing, HTTP, forms, dependency injection, testing utilities and a build toolchain — and dictates the structure your code lives in. The benefit is consistency across teams and projects; the cost is less freedom to assemble your own stack, which is the usual trade-off cited against a library-first approach.
What are the main building blocks of an Angular application?
FresherComponents, which pair a template with a class; directives, which add behaviour to elements; pipes, which transform values for display; services, which hold reusable logic and state; and dependency injection, which wires services into the things that need them. Modules, or standalone components in modern Angular, group these together, and the router maps URLs to components. Naming these six and how they relate is what the question is really testing.
Why does Angular use TypeScript?
FresherTypeScript adds static types, interfaces, generics and decorators on top of JavaScript, and Angular's whole metadata-driven design depends on decorators. Types catch a large class of template and injection mistakes at build time rather than in the browser, and they make refactoring across a large codebase realistic. The compiler also enables strict template checking, which surfaces errors in HTML that would otherwise only appear at runtime.
What is the bootstrapping process of an Angular application?
2–5 yrsThe browser loads index.html, which contains the root component's selector element, and main.ts runs. main.ts calls bootstrapApplication with the root component and a list of providers — or, in the NgModule world, platformBrowserDynamic().bootstrapModule(AppModule). Angular then creates the root injector, compiles and instantiates the root component, and renders it into the placeholder element, after which the router takes over.
What is the difference between Angular and React architecturally?
2–5 yrsAngular is a full framework with dependency injection, a template language, built-in routing, forms and HTTP, and a compiler that processes templates ahead of time. React is a view library where JSX is plain JavaScript and routing, forms and data fetching come from the ecosystem. In interviews the useful contrast is that Angular standardises decisions for you — good for large teams and long-lived codebases — while React defers them to you, which is more flexible and more variable.
What is Ivy?
SeniorIvy is Angular's compilation and rendering engine, the default since version 9, replacing the older ViewEngine. It compiles each component independently into instructions rather than producing a monolithic factory, which enables much better tree shaking, smaller bundles, faster rebuilds and clearer template error messages. It is also what made features like standalone components and improved debugging APIs practical.
What does Angular's release cadence and LTS policy mean in practice?
2–5 yrsAngular ships a major version roughly every six months, and each major gets around six months of active support followed by twelve months of long-term support with critical and security fixes only. Because the gap between versions is small and the CLI provides update schematics, upgrading regularly is far cheaper than skipping several majors. Teams that fall three or four versions behind usually face a painful jump, which is why the practical answer is to upgrade every cycle.
Components & Lifecycle
What is a component in Angular?
FresherA component is the basic building block of an Angular UI, defined by a class decorated with @Component that pairs an HTML template with logic and styles. The decorator metadata specifies the selector, template (or templateUrl), and styles. Every Angular app has at least one root component, typically AppComponent, that the framework bootstraps.
What are Angular lifecycle hooks?
FresherLifecycle hooks are methods Angular calls at specific moments in a component or directive's life. The most common are ngOnInit (after the first inputs are set, used for initialization), ngOnChanges (when input properties change), ngOnDestroy (just before the component is removed, used for cleanup), and ngAfterViewInit (after the view and child views are initialized). Implementing the matching interface, such as OnInit, is recommended for type safety.
What do @Input, @Output, and @ViewChild do?
Fresher@Input lets a parent component pass data down into a child component's property, while @Output exposes an EventEmitter so the child can emit events up to the parent. @ViewChild gives a component a direct reference to a child component, directive, or DOM element in its template so it can call methods or read values. Together they handle component communication and direct template access.
List the lifecycle hooks in the order Angular calls them.
2–5 yrsngOnChanges (before the first render and on every input change), ngOnInit, ngDoCheck, ngAfterContentInit, ngAfterContentChecked, ngAfterViewInit, ngAfterViewChecked, and finally ngOnDestroy. The Content hooks run before the View hooks because projected content is resolved before the component's own view. The Checked variants run on every change detection cycle, while Init variants run only once.
What is the difference between ngOnInit and the constructor?
FresherThe constructor runs when the class is instantiated, before Angular has set any @Input values, so it should only be used for dependency injection and trivial field setup. ngOnInit runs after the first binding pass, so inputs are populated and it is the right place for initialisation logic such as fetching data. Putting an HTTP call in the constructor also makes the component much harder to test.
When is ngOnChanges called and what does SimpleChanges contain?
2–5 yrsIt is called before ngOnInit and again whenever a data-bound @Input changes, receiving a SimpleChanges object keyed by input name with previousValue, currentValue and a firstChange flag. It only fires when the reference changes, so mutating a property inside an object you passed in will not trigger it. That reference-comparison rule is the single most common source of "my child component did not update" bugs.
Why is ngDoCheck expensive and when would you use it?
SeniorngDoCheck runs on every single change detection cycle for that component — potentially many times a second — so anything non-trivial inside it becomes a permanent performance cost. You use it only when you need to detect a change Angular cannot see by reference, such as a mutation inside an array or object input, usually with a KeyValueDiffer or IterableDiffer. The better answer is normally to use immutable updates so ngOnChanges fires instead.
What is the difference between ngAfterViewInit and ngAfterContentInit?
2–5 yrsngAfterContentInit fires once after content projected into the component through ng-content has been initialised, so @ContentChild queries are resolved. ngAfterViewInit fires once after the component's own template and its child components are initialised, so @ViewChild references are available. If you change a bound value inside ngAfterViewInit you will typically hit ExpressionChangedAfterItHasBeenCheckedError in development mode.
What should you clean up in ngOnDestroy?
2–5 yrsManual subscriptions, intervals and timeouts, event listeners added directly to the DOM or window, WebSocket connections, and any registration in a service that points back at the component. Anything left behind keeps the component instance reachable, so it never gets collected — an Angular memory leak is almost always a subscription or a listener. Using the async pipe or takeUntilDestroyed removes most of this work.
How do two sibling components communicate?
2–5 yrsThe standard approach is to lift the state into their common parent and pass it down with @Input while listening to @Output events from each child. When the components are far apart in the tree, a shared service holding a BehaviorSubject or a signal is the usual answer, with both siblings injecting it. Reaching for a global store is reasonable for genuinely application-wide state, and overkill for two components that happen to sit next to each other.
What is view encapsulation in Angular?
2–5 yrsBy default Angular uses Emulated encapsulation: it rewrites your component styles with generated attribute selectors so they apply only to that component's elements, without needing native shadow DOM. ShadowDom uses the browser's real shadow DOM for true isolation, and None disables scoping entirely so the styles become global. Setting None on a shared component is a common cause of styles leaking across an application.
Templates, Data Binding & Directives
What are the types of data binding in Angular?
FresherAngular supports interpolation ({{ value }}) and property binding ([property]) for one-way binding from component to view, event binding ((event)) for one-way binding from view to component, and two-way binding ([(ngModel)]) which combines property and event binding. Interpolation and property binding push data into the DOM, while event binding listens for user actions. Two-way binding keeps the model and view in sync automatically.
What is the difference between structural and attribute directives?
FresherStructural directives change the DOM layout by adding or removing elements, and are prefixed with an asterisk, such as *ngIf, *ngFor, and *ngSwitch. Attribute directives change the appearance or behavior of an existing element, such as ngClass, ngStyle, or a custom highlight directive. The key difference is that structural directives alter DOM structure while attribute directives only modify existing elements.
What is the difference between interpolation and property binding?
FresherInterpolation converts the expression to a string and inserts it into the template, so it is for text content. Property binding assigns the raw value to a DOM property, so it preserves types — [disabled]="false" actually sets the boolean, while disabled="{{false}}" sets the string "false", which is truthy. Use interpolation for text and property binding for anything that is not a string.
What is the difference between an HTML attribute and a DOM property in a template?
2–5 yrsAttributes are defined in the markup and set the initial value; properties live on the DOM object and hold the current value. Angular's square-bracket binding targets properties, which is why changing the value attribute of an input after the user types does nothing while binding the property does. For attributes with no matching property — colspan, aria-* — you need attribute binding, written [attr.colspan].
How do you use *ngIf with an else block?
2–5 yrsYou give the alternative content an ng-template with a reference variable and point at it: *ngIf="user; else loading", with <ng-template #loading>…</ng-template> elsewhere in the template. There is also a then clause for the true branch, and an "as" syntax to alias the value, such as *ngIf="user$ | async as user". In modern Angular the built-in @if / @else blocks express the same thing without ng-template.
What is the difference between ngClass and ngStyle?
FresherngClass adds or removes CSS classes based on a string, array or object of class-to-boolean pairs, while ngStyle sets inline style properties from an object of property-to-value pairs. Prefer ngClass, because the styling stays in the stylesheet where it can be themed and overridden; ngStyle is for genuinely dynamic values such as a computed width. There are also single-item shorthands, [class.active] and [style.width.px].
Can you put two structural directives on the same element?
2–5 yrsNo — Angular throws, because each structural directive claims the element's template and there is no defined order between them. The fix is to wrap one in an ng-container, which groups elements without adding a DOM node, or to move the condition into the loop expression. With the modern @if and @for blocks you can nest them directly, which is one of the reasons that syntax was introduced.
How do you write a custom attribute directive?
2–5 yrsCreate a class decorated with @Directive and a bracketed selector such as [appHighlight], inject ElementRef and Renderer2, and use @HostListener for events and @HostBinding for properties on the host element. Inputs work exactly as they do on components, so the directive can be configured from the template. Use Renderer2 rather than touching nativeElement directly so the directive still works in server-side rendering.
What are template reference variables?
FresherA template reference variable, declared with a hash such as #input, gives you a handle on a DOM element, a component instance or a directive inside the template. You can use it directly in the template — for example passing input.value into an event handler — or query it from the class with @ViewChild. Adding an exportAs name to a directive lets a reference variable point at the directive rather than the element.
What is $event in an event binding?
FresherIt is the payload of the event being bound. For a native DOM event it is the DOM event object, so (input)="onInput($event)" gives you access to $event.target.value. For a component's @Output it is whatever value the EventEmitter emitted, which is why a custom event can hand you a typed object rather than a DOM event. Casting $event.target in a strictly typed template is a common friction point.
What is the safe navigation operator in an Angular template?
FresherThe question mark in {{ user?.address?.city }} short-circuits to null instead of throwing when part of the chain is null or undefined. It matters because template data often arrives asynchronously, so the first render happens before the object exists. There is also a non-null assertion for the strict template compiler, but reaching for it usually means the type is wrong rather than the template.
What is the difference between ng-template, ng-container and ng-content?
Seniorng-template defines a block of markup that is not rendered until something instantiates it — structural directives compile down to it. ng-container is a grouping element that applies a directive to several elements without adding a wrapper node to the DOM. ng-content is the placeholder where content projected from a parent is inserted. They are frequently confused because all three are invisible in the output for different reasons.
What is the built-in control flow syntax in modern Angular?
2–5 yrsAngular now provides @if, @else, @for and @switch blocks directly in the template, replacing *ngIf, *ngFor and *ngSwitch. They need no imports, read more like ordinary code, allow nesting without ng-container, and @for requires a track expression, which makes list keying explicit rather than optional. The compiler also generates more efficient code for them, and the CLI ships a migration schematic to convert existing templates.
Pipes & Content Projection
What are pipes in Angular?
FresherPipes transform data directly in the template for display purposes without changing the underlying value. Angular ships with built-in pipes like date, currency, uppercase, json, and async, and you apply them with the pipe character, such as {{ price | currency }}. You can also create custom pipes by implementing the PipeTransform interface. The async pipe is especially useful because it subscribes to an Observable and unsubscribes automatically.
What is the difference between a pure and an impure pipe?
2–5 yrsA pure pipe — the default — only re-runs when its input reference or primitive value changes, so it is cheap. An impure pipe, declared with pure: false, runs on every change detection cycle, which is why it can detect mutations inside an object or array but also why it can wreck performance. Filtering or sorting a list with an impure pipe is a well-known anti-pattern; do it in the component instead.
What does the async pipe do and why is it preferred?
2–5 yrsIt subscribes to an Observable or Promise, returns the latest value to the template, and unsubscribes automatically when the component is destroyed, which removes the most common source of Angular memory leaks. It also calls markForCheck, so it works correctly with OnPush change detection. The trap is using it multiple times on the same cold observable, which creates a subscription each time — alias it once with @if or the "as" syntax, or use shareReplay.
How do you create a custom pipe?
FresherWrite a class decorated with @Pipe({ name: 'myPipe' }) that implements PipeTransform, and put the logic in transform(value, ...args). Declare it in a module or mark it standalone, then use it in a template as {{ value | myPipe }}. Keep it pure and side-effect free — a pipe that mutates its input or performs I/O will behave unpredictably because you do not control how often it is called.
Can a pipe take arguments?
FresherYes — anything after a colon is passed as an additional parameter to transform, and you can chain several, as in {{ date | date:'shortDate' }} or {{ amount | currency:'INR':'symbol' }}. Pipes can also be chained together with more pipe characters, evaluated left to right. Arguments participate in the purity check, so changing an argument re-runs a pure pipe.
Why should you avoid calling a component method from a template?
SeniorA method call in a binding is re-evaluated on every change detection cycle, which for a default-strategy component can be many times per second and per list item. It also returns a new reference each time if it builds an object or array, which defeats OnPush downstream. Use a pure pipe, a precomputed field, or a signal or observable instead, so the work happens only when the inputs actually change.
What is content projection in Angular?
2–5 yrsContent projection lets a parent pass markup into a child component, which renders it wherever it places an ng-content element — the Angular equivalent of slots or children. It is how you build generic wrappers such as cards, dialogs and layout shells that control structure without knowing what goes inside. The projected content belongs to the parent, so its bindings and injected services resolve in the parent's context, not the child's.
What is the difference between single-slot and multi-slot content projection?
SeniorA single unqualified ng-content takes everything the parent passes. Multi-slot projection adds a select attribute — ng-content select="[card-header]" — so different parts of the projected markup land in different places, with any unqualified ng-content catching the rest. A subtlety worth mentioning is that content is projected once and not duplicated, so two ng-content elements with the same selector will not both render it.
What is the difference between ViewChild and ContentChild?
SeniorViewChild queries elements in the component's own template; ContentChild queries elements projected into it through ng-content. They resolve at different times — ContentChild by ngAfterContentInit, ViewChild by ngAfterViewInit — which is why reading a ViewChild in ngOnInit gives undefined. Both have plural forms returning a QueryList, and a static option for when the element is not inside a structural directive.
Services & Dependency Injection
What is dependency injection in Angular?
FresherDependency injection (DI) is a design pattern where a class receives its dependencies from an external source rather than creating them itself. Angular has a built-in hierarchical DI system: you mark a class with @Injectable, register it as a provider, and Angular supplies the instance through the constructor. This promotes loose coupling, reusability, and easier testing through mocking.
What is a service in Angular?
FresherA service is a class that holds reusable business logic, data access, or shared state that is not tied to any specific view. Services are typically decorated with @Injectable and injected into components or other services via dependency injection. Using providedIn: 'root' registers the service as a singleton available across the whole app.
What is a provider and where can you register one?
2–5 yrsA provider tells the injector how to create a dependency for a given token. You can register it with providedIn on the @Injectable decorator, in an application-level providers array, in a module's providers, or in a component's or directive's providers array. Where you register it determines both its lifetime and who can see it, which is the whole point of Angular's hierarchical injector.
What is the difference between providedIn root and a component-level provider?
2–5 yrsprovidedIn: 'root' creates one instance for the whole application, and it is tree-shakable — if nothing injects the service, it is dropped from the bundle. Listing a service in a component's providers array creates a new instance for every instance of that component, destroyed with it. Use root for shared state and caches, and component-level providers when each component genuinely needs its own isolated state.
How does Angular's hierarchical injector resolve a dependency?
SeniorAngular first walks the element injector tree upward from the requesting component through its parent components, and if the token is not found it falls through to the module or environment injector chain, ending at the root injector, throwing NullInjectorError if it never matches. The first provider found wins, which is what makes a component-level provider shadow the root one. Decorators such as @Optional, @Self, @SkipSelf and @Host let you constrain that search.
What is an InjectionToken and when do you need one?
SeniorA class can act as its own DI token, but interfaces and primitives cannot, because TypeScript types do not exist at runtime. An InjectionToken creates a unique, typed token for injecting configuration objects, strings, feature flags or a browser API. It is also how you build multi-providers — several implementations registered against the same token with multi: true, collected into an array, which is how interceptors and validators are registered.
What is the difference between useClass, useValue, useFactory and useExisting?
SenioruseClass instantiates a different class for the token, which is how you swap a real service for a mock. useValue supplies a ready-made object or primitive, ideal for configuration. useFactory calls a function to build the value, with a deps array for its own dependencies, when construction requires logic. useExisting aliases one token to another so both resolve to the same single instance, rather than creating a second one as useClass would.
What is the inject() function and how does it differ from constructor injection?
2–5 yrsinject() retrieves a dependency from the current injection context without a constructor parameter, so it works in field initialisers, factory functions, route guards and resolvers written as plain functions. It reduces constructor boilerplate and composes better with inheritance, since a subclass no longer has to repeat and forward every parent dependency. The constraint is that it can only be called inside an injection context — calling it later, for example inside a callback, throws.
How do you share state between unrelated components?
2–5 yrsPut the state in a root-provided service and expose it as a BehaviorSubject, or as a signal in modern Angular, so both components read the same source and re-render when it changes. Expose the value as a read-only observable or computed signal and mutate it only through methods on the service, so changes go through one place. For large applications with complex flows a dedicated store gives you devtools and stricter conventions, at the cost of more ceremony.
What happens if two components both provide the same service?
2–5 yrsEach gets its own instance, because each component creates its own node injector entry, and any child components inject the nearest one. That is intentional and useful — a form component that provides its own state service can be reused several times on a page without them interfering. It is also a common accident: adding a service to a component's providers instead of root silently breaks the singleton other code assumed.
Modules & Standalone Components
What is an NgModule and why is it used?
FresherAn NgModule is a class decorated with @NgModule that groups related components, directives, pipes, and services into a cohesive block of functionality. Its metadata includes declarations, imports, providers, and exports. Every app has a root module (AppModule), and feature modules help organize large apps and enable lazy loading. Modern Angular also supports standalone components that work without NgModules.
What is the difference between declarations, imports, exports and providers in an NgModule?
Fresherdeclarations lists the components, directives and pipes that belong to this module. imports lists other modules whose exported declarables this module needs. exports lists which of this module's declarables other modules may use. providers registers services with the injector. The rule that trips people up is that declarations are private by default — a component is invisible to other modules unless it is exported.
What is a standalone component?
2–5 yrsA standalone component sets standalone: true and declares its own template dependencies in its imports array, so it needs no NgModule at all. It removes the indirection of finding which module declares a component, makes lazy loading a single component straightforward with loadComponent, and simplifies testing. Standalone is now the default for new components generated by the CLI, and NgModules remain supported for existing code.
What is a feature module?
FresherA feature module groups everything belonging to one area of the application — its components, its routing and its services — so the codebase is organised by domain rather than by file type. It keeps the root module small, makes ownership clear across teams, and is the unit the router lazy loads. The standalone equivalent is a folder with its own routes file loaded by loadChildren.
What is a shared module and what belongs in it?
2–5 yrsA shared module exports the declarables that many feature modules need — common UI components, directives, pipes, and re-exports of CommonModule and form modules. It should not provide services, because a shared module imported into a lazy-loaded module creates a second instance of anything it provides. Services belong in root, and with standalone components the whole pattern is usually replaced by importing components directly.
Why can a component be declared in only one NgModule?
2–5 yrsBecause declaring it defines which module owns its compilation context — its template dependencies and its injector scope — and two owners would be ambiguous, so Angular throws at build time. If several modules need the same component, declare it once in a shared module and export it, then import that module wherever it is needed. Standalone components sidestep this entirely, since ownership moves to the component itself.
What is the difference between forRoot and forChild?
SeniorIt is a convention for modules that carry both declarables and singleton services. forRoot returns the module with its providers and is called exactly once, in the root module; forChild returns the module without those providers for feature modules. RouterModule uses it so that the router service is a singleton while each feature still registers its own routes. Calling forRoot in a lazy module creates a duplicate service and produces very confusing bugs.
How do you bootstrap a standalone Angular application?
2–5 yrsmain.ts calls bootstrapApplication(AppComponent, { providers: [...] }) instead of bootstrapping a module. Application-wide configuration is supplied through provider functions such as provideRouter, provideHttpClient and provideAnimations, which are tree-shakable in a way that importing whole modules is not. There is no AppModule at all, and each component brings its own template dependencies.
Routing
How does routing work in Angular?
FresherThe Angular Router maps URL paths to components, enabling navigation in a single-page application without full page reloads. You define routes as an array of path-to-component mappings, register them with RouterModule.forRoot, and use a router-outlet directive as the placeholder where the matched component renders. The routerLink directive handles navigation, and route guards like CanActivate can control access.
What is lazy loading in Angular?
2–5 yrsLazy loading defers loading a feature module or component until the user actually navigates to its route, rather than loading everything upfront. This reduces the initial bundle size and speeds up the application's first load. It is configured in the route definition using a loadChildren or loadComponent function that dynamically imports the module or standalone component.
What are route guards and what types are there?
2–5 yrsGuards are functions the router runs before completing a navigation, returning true, false, or a UrlTree to redirect. CanActivate protects entry to a route, CanActivateChild protects its children, CanDeactivate asks whether it is safe to leave — the classic unsaved-changes prompt — and CanMatch decides whether a route configuration applies at all, which is what lets you avoid downloading a lazy bundle the user is not allowed to see. Guards are now plain functions using inject rather than classes.
How do you read route parameters, and what is the difference between snapshot and the params observable?
2–5 yrsInject ActivatedRoute and read route.snapshot.paramMap for a one-off value, or subscribe to route.paramMap for an observable that emits on every change. The snapshot is a trap when navigating between two instances of the same route — /product/1 to /product/2 — because Angular reuses the component and the snapshot never updates, so the observable is the safe default. Angular can also bind route params directly to component inputs with withComponentInputBinding.
What is a resolver and when would you use one?
SeniorA resolver fetches data before the route activates, so the component renders with its data already present instead of showing an empty state. That gives cleaner components and avoids a flash of empty content. The cost is that navigation appears to hang while the request runs, so you need a router loading indicator and a plan for failure; for slow or optional data, loading inside the component with a skeleton is usually the better experience.
What is the difference between routerLink and Router.navigate?
FresherrouterLink is a template directive that renders a real href, so links are crawlable, middle-clickable and accessible. Router.navigate and navigateByUrl are the programmatic API for navigating from code — after a successful save, from a guard, or in response to an event. Use routerLink whenever the navigation is a link the user clicks, and the Router service only when there is no anchor involved.
How do you handle a 404 in Angular routing?
FresherAdd a wildcard route with path: '**' pointing at a NotFound component, and place it last, because the router matches routes in order and the wildcard matches everything. A redirect route such as { path: '', redirectTo: '/home', pathMatch: 'full' } handles the empty path; forgetting pathMatch: 'full' there makes it match every URL prefix and creates an infinite redirect.
What are child routes and nested router outlets?
2–5 yrsA route can declare a children array, and the parent component's template contains its own router-outlet where those children render. This is how you build a layout with a persistent shell — a sidebar or tabs — while the inner area changes. Children can be lazy loaded too, and the parent route is a natural place to put guards and resolvers that apply to the whole section.
What is the difference between the hash and path location strategies?
2–5 yrsPathLocationStrategy uses the HTML5 History API and produces clean URLs, but the server must rewrite unknown paths to index.html or a refresh returns 404. HashLocationStrategy puts the route after a hash, which the server never sees, so it works on any static host with no configuration. Use path-based URLs by default — they are better for SEO and look normal — and hash only when you cannot configure the server.
How do you preload lazy-loaded routes?
SeniorPass a preloading strategy to provideRouter or RouterModule.forRoot: PreloadAllModules fetches every lazy bundle in the background once the app is idle, so the first load stays small but later navigations are instant. For large applications a custom PreloadingStrategy is better, preloading only routes flagged in their data, or based on connection quality. Preloading everything on a slow connection can compete with the requests the user is actually waiting on.
Forms & Validation
What is the difference between template-driven and reactive forms?
FresherTemplate-driven forms are built mostly in the HTML template using directives like ngModel and are simpler for small forms, with logic implicit in the template. Reactive (model-driven) forms are defined in the component class using FormControl, FormGroup, and FormBuilder, giving explicit, synchronous, and more testable control over form state and validation. Reactive forms are generally preferred for complex or dynamic forms.
What are FormControl, FormGroup, FormArray and FormBuilder?
FresherFormControl tracks the value and validation state of a single field. FormGroup composes named controls into an object-shaped form and aggregates their state. FormArray does the same for a variable-length list, which is how you build add-and-remove rows. FormBuilder is a service that removes the boilerplate of constructing them by hand, and its typed variants keep the form value strongly typed.
How do you add validators to a reactive form?
FresherPass them as the second argument when creating the control — Validators.required, minLength, max, email, pattern — or an array of them, with async validators as the third argument. You can change them later with setValidators followed by updateValueAndValidity, which people forget, leaving the control's status stale. Validators on a FormGroup are cross-field validators and receive the whole group.
How do you write a custom validator?
2–5 yrsA validator is a function taking an AbstractControl and returning null when valid or an object of error keys when not, such as { forbiddenName: true }. For a configurable validator, write a factory that returns that function. To validate across fields — password confirmation, date ranges — attach it to the FormGroup instead of the control, and read the error from the group in the template.
What is an async validator?
SeniorAn async validator returns a Promise or Observable of the error object or null, used for checks that need the server, such as whether a username is taken. It runs only after the synchronous validators pass, and while it is in flight the control's status is PENDING, which you should reflect in the UI. Debounce the input and switchMap the request, otherwise every keystroke fires a call and a slow earlier response can overwrite a newer one.
What is the difference between touched, dirty and pristine?
Freshertouched means the control has been blurred at least once; untouched means it has not. dirty means the value has been changed by the user, and pristine means it has not. They exist so you can delay showing errors until the user has actually interacted — the usual template condition is control.invalid && (control.touched || form.submitted) — rather than marking an empty form red on load.
How do you display validation errors in a template?
FresherRead the control from the form with form.get('email'), check its errors object, and show a message per error key inside a condition that also checks touched or submitted so errors do not appear before the user has typed. Keep the messages in one place — a small error component or a map of keys to text — rather than repeating conditions in every field. Also mark the message with aria-live and link it with aria-describedby so screen readers announce it.
What is the difference between setValue and patchValue?
2–5 yrssetValue requires an object matching the form structure exactly and throws if a key is missing or extra, which catches mistakes when you intend to replace the whole value. patchValue updates only the keys you provide and silently ignores unknown ones, which suits partial updates such as filling a few fields from an API. The silent ignoring is the trade-off: a typo in a key with patchValue fails quietly.
What is the difference between valueChanges and statusChanges?
2–5 yrsvalueChanges emits the new value whenever the control or group changes; statusChanges emits VALID, INVALID, PENDING or DISABLED whenever validity changes. Use valueChanges for autosave, dependent fields and search-as-you-type, usually with debounceTime and distinctUntilChanged. Remember that setValue triggers them unless you pass { emitEvent: false }, which is how you avoid an infinite loop when a subscription writes back into the form.
What is ControlValueAccessor and when do you implement it?
SeniorControlValueAccessor is the bridge between Angular's form API and a native or custom input, defining writeValue, registerOnChange, registerOnTouched and setDisabledState. You implement it when you build a custom form control — a rating widget, a rich text editor, a typeahead — so it works with formControlName, ngModel and validation like any built-in input. You register it as a multi-provider for NG_VALUE_ACCESSOR pointing at your component.
HttpClient & Interceptors
What is HttpClient and how is it different from fetch?
FresherHttpClient is Angular's HTTP API, returning Observables rather than Promises, with built-in JSON parsing, typed responses, an interceptor pipeline, progress events and testing utilities. fetch returns a promise, does not reject on 4xx or 5xx, and has no interception or cancellation story beyond AbortController. In an Angular app HttpClient is the default because interceptors and the HttpTestingController are hard to replicate.
Why does an HttpClient call not fire until you subscribe?
2–5 yrsHttpClient returns a cold observable, so the request is only issued when something subscribes; calling the method alone does nothing. Each subscription issues a separate request, which is why subscribing twice sends two calls, and why the async pipe used twice on the same observable duplicates work. Unsubscribing before the response arrives cancels the request, which is exactly how switchMap cancels a superseded search.
How do you send headers, query parameters and typed responses with HttpClient?
FresherPass an options object with headers and params, using HttpHeaders and HttpParams, both of which are immutable — calling set returns a new instance rather than mutating, which is a common source of "my header did not appear". Supply a generic type argument, as in http.get<User[]>(url), so the response is typed. Use observe: 'response' when you need status or headers, and responseType for blobs and text.
What is an HTTP interceptor and what is it used for?
2–5 yrsAn interceptor sits in the pipeline between your call and the network, able to inspect and clone the outgoing request and to transform or handle the incoming response stream. Typical uses are attaching an auth token, adding correlation ids, logging, showing a global loading indicator, retrying, and mapping errors. Requests are immutable, so you must clone them to modify — mutating the request object directly does nothing.
In what order do multiple interceptors run?
SeniorRequests pass through them in the order they are provided, and responses come back in the reverse order, like middleware. So an interceptor registered first sees the request first and the response last, which matters for a logger that should measure the whole round trip, or for an error handler that must sit outside a retry. Functional interceptors registered with withInterceptors follow the same ordering rule.
How do you handle HTTP errors globally in Angular?
2–5 yrsAdd an interceptor that pipes catchError over the response stream, maps HttpErrorResponse into a domain error, and decides what to do by status — refresh the token and retry on 401, redirect on 403, show a toast on 5xx. Rethrow with throwError so the caller can still react where the context matters. Swallowing every error in the interceptor is the mistake, because components then cannot distinguish failure from an empty result.
How do you retry a failed HTTP request?
2–5 yrsPipe retry with a delay or backoff configuration, or use retryWhen-style logic to add exponential backoff and a cap on attempts. Only retry idempotent requests — retrying a POST can create duplicate records — and only for transient failures such as timeouts, 429 and 5xx, never for a 400 or 401 that will fail identically. Honour a Retry-After header when the server sends one.
How do you cancel an in-flight HTTP request?
SeniorUnsubscribe from the observable — HttpClient aborts the underlying request. In practice you let an operator do it: switchMap cancels the previous request when a new value arrives, which is the correct behaviour for a search box, and takeUntil or takeUntilDestroyed cancels when the component is destroyed. Using mergeMap instead of switchMap for a typeahead is the classic bug, because a slow early response can land after a newer one.
RxJS in Angular
What is the difference between an Observable and a Promise?
FresherA Promise handles a single asynchronous value and executes immediately, while an Observable (from RxJS) can emit multiple values over time and is lazy, running only when subscribed. Observables are cancellable via unsubscribe and support powerful operators like map, filter, and switchMap. Angular uses Observables heavily, for example in HttpClient and reactive forms.
Which RxJS operators do you use most in Angular?
2–5 yrsmap and filter for shaping values, switchMap for dependent requests, catchError for error handling, tap for side effects, debounceTime and distinctUntilChanged for input handling, startWith for an initial value, shareReplay for caching a response across subscribers, and takeUntil or takeUntilDestroyed for teardown. Knowing which category an operator belongs to — transformation, filtering, combination, error handling, multicasting — is more useful than memorising a long list.
What is the difference between map and switchMap?
2–5 yrsmap transforms each emitted value synchronously and returns a plain value. switchMap expects you to return another observable and flattens it, so it is what you use when one stream triggers another async call. Using map where the callback returns an observable gives you an observable of observables, which is why the template shows [object Object] — a very common early mistake.
What is the difference between switchMap, mergeMap, concatMap and exhaustMap?
SeniorThey differ in what happens when a new value arrives while an inner observable is still running. switchMap cancels the previous one — right for search and for navigation-driven loads. mergeMap runs them all concurrently, so order is not guaranteed. concatMap queues them and preserves order, which suits sequential writes. exhaustMap ignores new values until the current one finishes, which is the correct choice for a submit button so a double click cannot fire twice.
What is a Subject, and how do BehaviorSubject, ReplaySubject and AsyncSubject differ?
SeniorA Subject is both an observable and an observer, so it can multicast values you push into it — the usual way a service exposes state. BehaviorSubject requires an initial value and gives every new subscriber the current one, which is what state usually needs. ReplaySubject replays a configurable number of past values to late subscribers, and AsyncSubject emits only the final value on completion. Expose them as observables with asObservable so callers cannot push into your state.
What is the difference between a cold and a hot observable?
SeniorA cold observable creates its producer per subscription, so each subscriber gets an independent execution — an HttpClient call is cold, which is why two subscriptions send two requests. A hot observable shares one producer among all subscribers, so late subscribers miss earlier values; DOM events and Subjects are hot. shareReplay converts a cold source into a shared, replayed one, which is how you cache a request across components.
How do you avoid memory leaks from subscriptions in Angular?
2–5 yrsPrefer the async pipe, which subscribes and unsubscribes with the component. Where you must subscribe manually, tear down in ngOnDestroy using takeUntil with a destroy subject, takeUntilDestroyed, or a Subscription that collects children with add. Note that a finite observable such as a single HttpClient call completes on its own, so the real risk is with long-lived sources: subjects in services, router events, form valueChanges, and interval or fromEvent streams.
What is the takeUntil destroy-subject pattern?
2–5 yrsYou create a private Subject, pipe every long-lived subscription through takeUntil(this.destroy$), and in ngOnDestroy call next() then complete() on it, which unsubscribes them all at once. takeUntil must be the last operator in the pipe, otherwise operators after it can resubscribe and keep the chain alive. In modern Angular takeUntilDestroyed from @angular/core/rxjs-interop replaces the boilerplate entirely.
What is takeUntilDestroyed?
2–5 yrsIt is an operator that ties a subscription to the current injection context's destroy lifecycle, so no destroy subject and no ngOnDestroy are needed. Called in a field initialiser or constructor it picks up DestroyRef automatically; called later you must pass a DestroyRef explicitly. It is the recommended teardown mechanism in current Angular, and it pairs with toSignal and toObservable for bridging between signals and RxJS.
How would you implement a type-ahead search with RxJS?
SeniorTake the form control's valueChanges, then debounceTime around 300 milliseconds, distinctUntilChanged to ignore repeats, filter out inputs that are too short, and switchMap into the HTTP call so an obsolete request is cancelled. Wrap the inner call in catchError returning an empty result so one failure does not kill the outer stream, and render with the async pipe. The two mistakes interviewers look for are using mergeMap instead of switchMap, and letting an error terminate the subscription permanently.
What is the difference between combineLatest, forkJoin and zip?
SeniorcombineLatest emits whenever any source emits, giving the latest value from each — right for live values like filters and form state, but it emits nothing until every source has emitted at least once. forkJoin waits for all sources to complete and emits their final values once, which suits parallel HTTP calls, but it emits nothing at all if any source errors or never completes. zip pairs emissions by index, so it is only correct when the streams are genuinely in lockstep.
Change Detection & Performance
What is change detection in Angular?
2–5 yrsChange detection is the mechanism Angular uses to keep the DOM in sync with the component's data. By default it uses the Zone.js library to detect asynchronous events (clicks, HTTP responses, timers) and then checks the component tree for changes. You can optimize performance by setting a component's changeDetection to OnPush, which only re-checks when input references change or events fire within the component.
What is the difference between AOT and JIT compilation?
2–5 yrsJust-in-Time (JIT) compilation compiles the application in the browser at runtime, which is convenient during development but slower to start. Ahead-of-Time (AOT) compilation compiles the templates and components during the build, producing smaller, faster bundles and catching template errors earlier. AOT is the default for production builds in modern Angular.
What is Zone.js and what does it do?
SeniorZone.js monkey-patches browser async APIs — setTimeout, event listeners, XHR, promises — so Angular is notified whenever any of them completes and can run change detection without you calling it. That is why bindings update automatically after a click or an HTTP response. The cost is that every async event triggers a check of the whole tree, which is why zoneless Angular with signals is the direction the framework is moving.
What is the difference between the Default and OnPush change detection strategies?
2–5 yrsDefault checks every component in the tree on every cycle, comparing every binding. OnPush skips a component and its subtree unless one of a few things happens: an @Input reference changes, an event fires inside the component, an async pipe in its template emits, or something calls markForCheck. This turns a full-tree check into a targeted one, and is the single highest-impact change on a large Angular page.
What actually triggers change detection in an OnPush component?
SeniorA new reference on an @Input, a DOM event handled by the component, an async pipe emitting in its template, or an explicit ChangeDetectorRef.markForCheck — often from a signal update in newer versions. Mutating an object or pushing into an array that was passed in does not, because the reference is unchanged, which is why OnPush demands immutable updates. Data arriving through a service subscription without markForCheck is the other classic "the UI does not update" case.
What is the difference between markForCheck and detectChanges?
SeniormarkForCheck marks the component and all its ancestors as dirty so they will be checked during the next cycle; it does not run detection immediately. detectChanges runs detection synchronously on that component and its children right now. detach and reattach let you take a subtree out of the cycle entirely for extreme cases such as a high-frequency chart. Reaching for detectChanges to force a refresh usually means a reference was mutated somewhere it should not have been.
What are Angular signals?
2–5 yrsSignals are reactive values you read as a function call: writable signals with signal(), derived values with computed(), and side effects with effect(). Because a template records exactly which signals it read, Angular can update only the affected view rather than checking a whole component tree, which is what makes zoneless change detection possible. They interoperate with RxJS through toSignal and toObservable, so you can adopt them incrementally.
Why do you need trackBy in *ngFor?
2–5 yrsWithout it Angular tracks list items by object identity, so a refetch that returns equivalent but newly constructed objects makes it destroy and recreate every DOM node and component in the list. Supplying a trackBy that returns a stable id lets Angular reuse the existing nodes and touch only what really changed, which preserves focus and animation state as well as performance. The modern @for block makes this mandatory by requiring a track expression.
What causes ExpressionChangedAfterItHasBeenCheckedError?
SeniorIn development mode Angular runs a second verification pass after each change detection cycle; if a bound value differs from the first pass, it throws, because the view and the model have diverged mid-cycle. It is typically caused by changing state in ngAfterViewInit or a child emitting into a parent during rendering. Fixes are to move the update earlier, to make the child emit asynchronously, or as a last resort to call detectChanges — but the error is a real warning that data is flowing the wrong way.
How would you improve the performance of a slow Angular application?
SeniorProfile first with the Angular DevTools change detection profiler and a production build, since development mode double-checks everything. Then work down the usual list: OnPush or signals to cut the checked tree, trackBy on lists, virtual scrolling for long lists, no method calls or impure pipes in templates, lazy loading and preloading for route bundles, unsubscribing to stop dead components doing work, and deferrable views for below-the-fold blocks. Check the bundle with a source-map analyser before assuming rendering is the problem.
Testing, CLI & Tooling
What is TestBed and what does it do?
2–5 yrsTestBed builds a miniature Angular module for a test — declaring or importing the component under test, providing stubs for its dependencies, and compiling the template. TestBed.createComponent returns a ComponentFixture giving access to the instance, the rendered DOM through debugElement, and detectChanges to run change detection. Anything that depends on Angular's DI or template rendering needs TestBed; a plain service with no Angular dependencies does not.
What is the difference between a shallow and a deep component test?
SeniorA shallow test replaces child components with stubs, or uses NO_ERRORS_SCHEMA, so it exercises only the component under test — fast, focused, and unaffected by changes in children. A deep test renders the real child tree, which catches integration mistakes but is slower and fails for reasons unrelated to the component. Most suites use shallow tests by default with a few deep tests over critical flows.
How do you test a component that depends on a service?
2–5 yrsProvide a substitute in the TestBed providers — a jasmine or jest spy object, a hand-written fake, or the real service with HttpClientTestingModule so requests are intercepted rather than sent. Keeping the dependency injected rather than constructed inside the component is exactly what makes this possible, which is the practical argument for DI. Assert on the rendered output where you can, rather than on internal fields, so the test survives refactoring.
What are fakeAsync and tick used for?
SeniorfakeAsync runs a test in a zone where timers and microtasks are queued rather than executed, and tick(ms) advances that virtual clock so you can test debouncing, setTimeout and promise resolution synchronously and deterministically. flush drains all pending timers, and discardPeriodicTasks clears intervals that would otherwise fail the test. The alternative, waitForAsync with fixture.whenStable, is better when real async work such as template compilation is involved.
How do you test a service that returns an observable?
2–5 yrsSubscribe and assert inside the subscription, using done or an async test so the assertion actually runs, or use HttpTestingController to expect a request, flush a response, and then verify no requests are outstanding. For time-based streams, marble testing with TestScheduler expresses timing far more clearly than nested subscriptions. The common failure is a test that passes because the assertion never executed.
What is the Angular CLI and which commands do you use most?
FresherThe CLI scaffolds, builds, tests and serves an Angular project with a consistent configuration. The commands that matter day to day are ng new, ng generate (component, service, guard, pipe), ng serve for the dev server, ng build for a production bundle, ng test, and ng update for version migrations. Generating through the CLI rather than by hand keeps naming, file structure and registration consistent across a team.
What does a production build do differently?
2–5 yrsIt compiles ahead of time, enables optimisation and minification, tree-shakes unused code, hashes filenames for cache busting, strips development-only checks such as the second change detection pass, and applies budget limits that fail the build if a bundle grows past a threshold. It also swaps in production file replacements if configured. This is why a performance measurement taken with ng serve is not meaningful.
What is a schematic in Angular?
SeniorA schematic is a code generator that transforms a project through a virtual file tree — it is what ng generate and ng add run, and what ng update uses to migrate breaking changes automatically. You can write your own to scaffold team-specific patterns or to codemod an internal API change across a large repository. Because they operate on a virtual tree, they can be run in dry-run mode and reviewed before anything is written.
How do you upgrade an Angular application to a new major version?
SeniorUse ng update one major at a time, following the official update guide for that version pair, with a clean git tree so the schematic changes are reviewable. Upgrade Angular packages and their peer dependencies together, run the test suite after each step, and deal with deprecations before they become removals. Skipping versions is the mistake, because migration schematics are written for a single-step jump.
Get these answered live in your real interview
NostrobeAI is a real-time AI interview copilot — it hears the question and drafts a strong answer on your screen, invisible on Zoom, Meet, and Teams. One-time pricing, no subscription.
Try NostrobeAI free