67 Angular interview questions with detailed answers, sorted from basic to advanced. Free to practice, with progress saved automatically.
Angular is a full framework for building web applications in TypeScript, shipping with routing, forms, an HTTP client and dependency injection. The bank covers components and templates, lifecycle hooks, signals and change detection, dependency injection, the Router, typed Reactive Forms, HttpClient with RxJS, SSR and hydration, and testing with TestBed.
and 5 more topics.
Angular is a full-featured TypeScript frontend framework for SPAs, enterprise apps and hybrid-rendered web apps. AngularJS refers to the old 1.x line, has a completely different architecture (support ended at the end of 2021), and should not be confused with modern Angular. Compared with React…
A component is the main building block of Angular UI. It usually contains a TypeScript class for state and logic, an HTML template for bindings, component-scoped CSS, and @Component metadata such as selector, templateUrl, styleUrl, and imports. With standalone components, dependencies are declared directly in…
A standalone component manages its own dependencies through the imports array in the @Component decorator and can be bootstrapped directly with bootstrapApplication() without an NgModule. Since Angular 19, components are standalone by default, so you no longer write standalone: true. Main benefits: - Less boilerplate:…
Bootstrap is the startup step of the app: Angular builds the root injector from the providers list, creates the root component, and attaches it to the tag matching its selector in index.html. In a standalone app, this step is the call bootstrapApplication(rootComponent, config) in main.ts,…
An NgModule is a class decorated with @NgModule. It declares which components belong together and provides providers for that part of the app. Since Angular 19, components, directives and pipes are standalone by default: they declare what they use in imports, so a new app…
Lifecycle hooks are methods Angular calls at specific moments of a component's life: on creation, each time change detection (the pass where Angular updates the DOM to match new data) checks it, and on destruction. Order on the first render: 1. constructor — the class…
The Angular compiler analyzes templates before runtime, connects them with TypeScript types and catches issues such as wrong input names, invalid component input types, missing pipes or invalid template variables. Enabling strict template checking with "strictTemplates": true under angularCompilerOptions in tsconfig.json (projects created with ng…
Interpolation {{ value }} renders text in the template. Property binding [disabled]="isSaving()" sets a DOM property or component input from an expression. Event binding (click)="save()" listens to an event and calls a method. Quick rule: use {{ }} for text, [ ] to push data…
[(ngModel)] is the two-way binding syntax, also called banana-in-a-box because the [()] pair looks like a banana inside a box. It combines property binding and event binding: data flows down into the input, and input changes flow back into the model. [ngModel]="name" pushes the value…
input() or @Input() receives data from a parent into a child. output() or @Output() emits events from a child back to a parent. The standard pattern is one-way data flow: the parent owns state, the child receives inputs and emits events when users interact. Avoid…
input() creates an InputSignal that you read by calling it, for example userId(), and it composes naturally with computed() or effect(). Example: How it differs from @Input(): - Read-only: inside the component you cannot reassign this.userId = ...; only the parent changes the value. An…
model() defines a writable input and also creates a <nameChange output to support two-way binding for custom components. Example of a toggle button that updates its own value, with a parent binding two-way: The parent passes darkMode down through [(checked)]. When the user clicks, Toggle…
A directive is a class that attaches behavior to the DOM or a template. An attribute directive changes behavior or appearance of an existing element, such as highlight or permission state. A structural directive changes DOM structure by adding/removing views. In modern Angular, legacy ngIf,…
Control flow blocks are built-in template syntax, require no directive import and are easier to type-check. Example: Why block syntax is better: - No imports: @if/@for are part of the compiler, not directives, so you do not add NgIf/NgFor to imports and they do not…
track tells Angular which item represents the same entity when a list changes, allowing DOM/component instances to be reused instead of incorrectly destroyed and recreated. Correct example for data with ids: For static lists you can track the item; avoid index when the list can…
@defer lets you delay loading/rendering part of a template and its dependencies based on triggers such as viewport, interaction, hover, timer or idle. Example: Use it for UI that is not immediately needed to reduce initial bundle size and improve Core Web Vitals. The example…
ng-content lets a parent pass markup into a child component layout, similar to slots. Example card with title and body slots: Use it for wrapper components such as cards, modals, tabs or layout shells, where the child controls the frame and the parent controls the…
A signal is a reactive value read by calling a function, for example count(), and updated with set() or update(). When a signal is read in a template or computed, Angular tracks that dependency; when the value changes, dependent consumers update. Signals make local state…
These three APIs differ in writing, deriving, and running side effects: - signal: holds a value, read by calling it like a function (count()), written with set or update. - computed: derives a value from other signals, is read-only, and recomputes only when a signal…
A view query reads an element/component declared in the component's own template; a content query reads content projected by a parent through ng-content. Modern signal query example, with both kinds in one component: searchBox is written by Card in its own template, so you find…
An Observable represents a stream over time, supports cancellation, has powerful operators and fits HTTP, WebSocket, router events or async pipelines. A Signal represents a synchronous current value, is read directly in templates and fits local UI state. A signal always has a value, is…
ChangeDetectionStrategy.OnPush tells Angular to skip a component until a signal says its view may have changed. Angular checks the component again when one of these happens: - An input changes reference: Angular compares the old and new values with Object.is. - An event happens inside…
The async pipe subscribes to an Observable (or Promise) right in the template, renders the latest value, and unsubscribes automatically when the view is destroyed. You do not write subscribe and ngOnDestroy in the component, which lowers the risk of a forgotten unsubscribe causing a…
A pipe transforms data in a template. Pipes are pure by default: Angular reruns them only when a primitive changes or an object/array reference changes, which is better for performance. Custom pure pipe example: An impure pipe with pure: false can observe mutations inside objects/arrays,…
Dependency Injection is the mechanism where a class receives dependencies from an Angular injector instead of creating them with new. Users does not know how UserService is created; it only asks for it. The injector sees providedIn: 'root', creates a single instance and hands it…
providedIn: "root" registers a service in the root injector, usually as an app-wide singleton and tree-shakable when unused. Component provider example creating a separate store per wizard: A component provider creates an instance in that component injector and applies to the subtree below it. Use…
Constructor injection declares dependencies through constructor parameters and is explicit and familiar. inject() fetches a dependency with a function call, so it also works where there is no constructor. Example functional guard using inject(): Key differences: - Works outside classes: functional guards, resolvers and interceptors…
InjectionToken is for injecting something that is not a concrete class: a config object, a primitive value, a feature flag, an API URL, or an interface (an interface exists only at compile time and is gone at runtime, so it cannot be a token). The…
All four are ways to declare a provider as { provide: TOKEN, ... }. They differ in how Angular produces the value when someone calls inject(TOKEN): - useClass: Angular creates a new instance of the class you name. Used to swap an implementation, for example…
Angular Router maps URLs to components through route configuration. A standalone app usually uses provideRouter(routes), the template places <router-outlet / where the current route renders, and navigation uses routerLink or Router.navigate(). Visiting /users/42 renders UserDetail inside <router-outlet /, and it can read id = '42'.…
With standalone components, use loadComponent; for a feature with many child routes, use loadChildren to import a route array. Example: Set boundaries by real features/screens, not too small, otherwise request waterfalls increase.
No. A route guard only controls client-side navigation to improve UX, such as redirecting unauthenticated users or preventing navigation away from an unsaved form. Real security must live in backend/API authorization because users can call APIs directly or modify client code. Treat guards as a…
A resolver is a function that runs before a route activates: Angular waits for it to finish and only then shows the component. The component receives data that is already there, so it needs no loading state for the main data, and a data-loading error…
withComponentInputBinding() binds path params, query params, matrix params and route data into component inputs with matching names. Example: This makes components easier to test and less coupled to ActivatedRoute.
The preferred approach is to enable withComponentInputBinding(): the router assigns path params (the :id part of the path) and query params (the part after ?) to input()s with the same name in the component. For that URL, id() is '42' and tab() is 'posts'. If…
Typed Forms make FormControl, FormGroup and valueChanges carry correct TypeScript types, so the compiler catches wrong field names or submitting an object with missing or mistyped fields. Example: Two points that often come up: - nonNullable: true: by default reset() sets a control back to…
A validator is a function that receives an AbstractControl and returns ValidationErrors null. Example cross-field validator, attached to a FormGroup and shown in the template: This validator sits on the group, not on a single control, because one control cannot see its sibling. So the…
FormArray is for when the number of controls changes at runtime: a list of phone numbers, addresses, invoice line items, survey questions. A FormGroup has a fixed set of keys, while a FormArray is a list by index, and you add or remove entries with…
HttpClient is Angular's built-in service for calling HTTP APIs. Each call such as get() or post() returns an Observable, and that Observable is cold: it only describes the request and sends nothing until something calls subscribe. getUsers() only creates the Observable; no request has gone…
An interceptor handles cross-cutting concerns for requests/responses: attaching auth tokens, refreshing tokens, correlation ids, logging, retry, error normalization or loading indicators. Example functional interceptor: Keep interceptors thin; business transformations belong in API services.
switchMap cancels the previous request and keeps the latest, fitting search/autocomplete. Search box example: The user types "ang" then "angular": the "ang" request is cancelled and only the "angular" result is shown, so an old response can never arrive late and overwrite a newer one.…
Prefer the async pipe in templates because it unsubscribes automatically. When subscribing in a class, use takeUntilDestroyed() with DestroyRef: One-shot HTTP Observables complete on their own, but long-lived streams such as router events, form valueChanges, intervals, WebSockets or service Subjects still need care.
Handle HTTP errors at the right layer: component/store handles business errors that need specific UI; API services normalize responses; interceptors handle cross-cutting concerns such as auth, retry, correlation ids or global error logging. Controlled fallback example in a service: Do not swallow every error in…
SSR (server-side rendering) renders components to HTML on the server, so the browser receives a page that already has content. Hydration is the next step: Angular on the client picks up the exact DOM the server produced and attaches event listeners and state to it,…
A hydration mismatch happens when the DOM the client expects differs from the DOM the server rendered; Angular throws an error (usually NG0500) instead of guessing. Four common causes: - Direct DOM manipulation: appendChild or innerHTML inserting or moving nodes Angular does not know about.…
Start by measuring: which bundle is heavy and which chunk it sits in. Run ng build --stats-json to produce browser-stats.json, then open it with esbuild's analyzer (esbuild.github.io/analyze) to see which libraries take the most space. The goal is to reduce the JavaScript that must download…
Angular builds accessible components via semantic HTML, ARIA attributes, and @angular/cdk/a11y (stable), the a11y utility set widely used in production. Key CDK a11y tools: - FocusTrap (the cdkTrapFocus directive): keeps focus inside a modal/dialog so Tab cannot escape. - LiveAnnouncer: announces dynamic messages to screen…
animate.enter and animate.leave are newer animation APIs directly supported by the compiler, using CSS classes or callbacks when an element enters/leaves the DOM. Current Angular docs recommend native CSS with these APIs for new code; the whole legacy @angular/animations package has been deprecated since v20.2…
TestBed creates a testing module/environment to render components, inject services and override providers in unit tests. configureTestingModule sets up a small Angular environment holding only what the test needs. Here the real UserService is replaced by a fake object, so the test never calls a…
New projects created with the Angular CLI from Angular 21 use Vitest as the default test runner. Karma is still supported by the CLI (ng new --test-runner=karma) for existing projects, but the Karma package itself has been marked deprecated by its maintainers, so a new…
In a test you do not call a real server. provideHttpClientTesting() replaces the HttpClient backend with a fake one, and provides HttpTestingController so you can see which requests were sent and answer each one yourself. Step by step: - firstValueFrom(...) subscribes to the Observable, so…
Not every Angular app needs a global state library. State used by a single component should use signals; data fetched from a server can stay as Observables in a service; moderate feature state can use a small hand-written service or store. A small store built…
The constructor belongs to the TypeScript class and runs when Angular instantiates it — at that point @Input() values are not bound yet. ngOnInit is an Angular lifecycle hook that runs after the first ngOnChanges, when inputs are ready. Practical rule: - constructor: take dependencies…
Because a signal notifies based on reference comparison when you write a new value. items().push(x) only reads the signal and mutates the array in place — the signal never learns anything changed, so the template is not notified. - set(value): write a new value independent…
This error appears in dev mode only. After each change detection pass Angular runs a verification pass; if a binding's value differs from the first pass, something mutated state after the view was checked — Angular reports it because the view would display data inconsistent…
With OnPush, Angular checks the component only on one of these signals: an input reference change, an event from its own template, an async pipe emission, or a signal read in the template changing. Outside those, the view stays stale even though the data changed.…
takeUntilDestroyed() (from @angular/core/rxjs-interop) completes an Observable when the context is destroyed, replacing the manual destroy$ = new Subject() + ngOnDestroy pattern. NG0203 means you called an API requiring an injection context (inject(), or takeUntilDestroyed() with no argument) where Angular no longer provides one — inside…