Top 50 Angular Interview Questions
Curated questions covering components, directives, services, RxJS, routing, forms, signals, change detection, and Angular CLI.
What is Angular and what are its key features?
Angular is a TypeScript-based open-source front-end framework by Google. Key features: component-based architecture, two-way data binding, dependency injection, RxJS-based reactivity, Angular CLI, built-in routing, reactive and template-driven forms, and ahead-of-time (AOT) compilation.
What are Angular components?
Components are the building blocks of Angular applications. Each component has a TypeScript class decorated with @Component, an HTML template, and optional CSS styles. Components control a portion of the UI and communicate via @Input() and @Output().
@Component({\n selector: "app-user",\n template: `<h1>Hello, {{ name }}</h1>`,\n styles: [`h1 { color: red; }`]\n})\nexport class UserComponent {\n @Input() name = "";\n}
What is dependency injection in Angular?
Dependency Injection (DI) is a design pattern where Angular provides dependencies to components and services rather than having them create their own. Use the inject() function or constructor injection. Services are registered in providers arrays or with providedIn.
@Injectable({ providedIn: "root" })\nexport class UserService {\n getUsers() { return []; }\n}\n\n@Component({ ... })\nexport class AppComponent {\n private userService = inject(UserService);\n}
What is the difference between @Component, @Directive, and @Pipe?
- @Component - a directive with a template. Creates a UI element with its own view.
- @Directive - adds behavior to an existing DOM element without a template. Two types: structural (*ngIf, *ngFor) and attribute ([ngClass], [ngStyle]).
- @Pipe - transforms data in templates. Pure pipes only re-run when input reference changes; impure pipes run on every change detection cycle.
What is the difference between template-driven and reactive forms?
- Template-driven - form logic in the template using NgModel. Simple, less code, but harder to test and scale.
- Reactive - form logic in the component class using FormGroup, FormControl, FormBuilder. More explicit, testable, and scalable.
- Reactive forms are preferred for complex forms with dynamic validation.
// Reactive form\nthis.form = this.fb.group({\n email: ["", [Validators.required, Validators.email]],\n password: ["", Validators.minLength(8)]\n});
What is Angular change detection?
Change detection is the mechanism Angular uses to sync the component tree with the data model. Default strategy checks every component on every event. OnPush strategy only checks when an @Input() reference changes, an event originates from the component, or async pipe emits.
@Component({\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class UserComponent {}
What is the difference between ChangeDetectionStrategy.Default and OnPush?
- Default - Angular checks the entire component tree on every browser event, timer, or HTTP response. Simple but can be slow for large apps.
- OnPush - Angular only checks the component when its @Input() references change, an event fires from within it, or an Observable/async pipe emits. Much more performant.
What are Angular Signals?
Signals are a reactive primitive introduced in Angular 16+. signal() creates a reactive state, computed() derives values, effect() runs side effects. Signals enable fine-grained reactivity without Zone.js.
import { signal, computed, effect } from "@angular/core";\n\nconst count = signal(0);\nconst doubled = computed(() => count() * 2);\n\neffect(() => console.log("Count:", count()));\n\ncount.set(5); // set\ncount.update(n => n + 1); // update
What is the difference between Observable and Promise?
- Promise - handles a single async value; eager (starts immediately); not cancellable.
- Observable - handles a stream of values over time; lazy (starts on subscribe); cancellable; supports operators (map, filter, switchMap).
- Use Observables for HTTP, events, and streams; Promises for one-time async operations.
What is RxJS and what are the most used operators?
RxJS is a library for reactive programming using Observables. Key operators:
- map - transforms each emitted value.
- filter - emits only values that pass a test.
- switchMap - cancels previous inner Observable when a new value arrives. Used for HTTP requests.
- mergeMap - subscribes to all inner Observables concurrently.
- catchError - handles errors in the stream.
- takeUntil - completes Observable when another Observable emits.
What is the difference between switchMap, mergeMap, concatMap, and exhaustMap?
- switchMap - cancels previous inner Observable on new emission. Best for search/autocomplete.
- mergeMap - runs all inner Observables concurrently. Best for parallel requests.
- concatMap - queues inner Observables, runs one at a time in order. Best for sequential operations.
- exhaustMap - ignores new emissions while inner Observable is active. Best for login buttons.
// Search: cancel previous request on new keystroke\nthis.searchInput.valueChanges.pipe(\n debounceTime(300),\n switchMap(term => this.api.search(term))\n).subscribe();
What is the Angular Router and how do you configure routes?
The Angular Router enables navigation between views. Configure routes with provideRouter() or RouterModule.forRoot(). Use routerLink for navigation, ActivatedRoute for params, and Router service for programmatic navigation.
const routes: Routes = [\n { path: "", component: HomeComponent },\n { path: "users/:id", component: UserComponent },\n { path: "admin", loadChildren: () => import("./admin/admin.routes") },\n { path: "**", redirectTo: "" }\n];
What is lazy loading in Angular?
Lazy loading loads feature modules only when the user navigates to them, reducing the initial bundle size. Use loadChildren with dynamic import() in route config. Angular 17+ uses standalone components with loadComponent.
{ path: "admin", loadChildren: () =>\n import("./admin/admin.module").then(m => m.AdminModule) }\n\n// Standalone (Angular 17+)\n{ path: "admin", loadComponent: () =>\n import("./admin.component").then(c => c.AdminComponent) }
What are Angular Guards?
Guards control navigation. Types: CanActivate (can user enter route?), CanDeactivate (can user leave?), CanActivateChild (child routes), CanMatch (route matching), Resolve (pre-fetch data). Modern Angular uses functional guards.
// Functional guard (Angular 15+)\nexport const authGuard: CanActivateFn = (route, state) => {\n const auth = inject(AuthService);\n return auth.isLoggedIn() ? true : inject(Router).createUrlTree(["/login"]);\n};
What is the difference between ngOnInit and constructor in Angular?
- constructor - called by JavaScript when the class is instantiated. Use only for DI (injecting services). @Input() values are NOT available yet.
- ngOnInit - called by Angular after the component is initialized and @Input() values are set. Use for initialization logic, HTTP calls, and subscriptions.
What are Angular lifecycle hooks?
Lifecycle hooks let you tap into key moments of a component/directive lifecycle.
- ngOnChanges - called when @Input() values change.
- ngOnInit - called once after first ngOnChanges.
- ngDoCheck - called on every change detection run.
- ngAfterContentInit/Checked - after content projection.
- ngAfterViewInit/Checked - after view and child views are initialized.
- ngOnDestroy - cleanup before component is destroyed.
What is the async pipe and why is it preferred?
The async pipe subscribes to an Observable or Promise in the template and automatically unsubscribes when the component is destroyed. It eliminates manual subscription management and memory leaks.
// Component\nusers$ = this.userService.getUsers();\n\n// Template\n<ul>\n <li *ngFor="let user of users$ | async">{{ user.name }}</li>\n</ul>
What is the difference between ViewChild and ContentChild?
- @ViewChild - queries elements or components in the component's own template.
- @ContentChild - queries elements projected into the component via
. - Both are available after ngAfterViewInit / ngAfterContentInit respectively.
@ViewChild("myInput") inputRef!: ElementRef;\n@ContentChild(HeaderComponent) header!: HeaderComponent;
What is ng-content and content projection?
Content projection allows a component to accept and display external HTML content via
<!-- card.component.html -->\n<div class="card">\n <ng-content select="[card-title]"></ng-content>\n <ng-content></ng-content>\n</div>\n\n<!-- Usage -->\n<app-card>\n <h2 card-title>Title</h2>\n <p>Body content</p>\n</app-card>
What is the difference between Subject, BehaviorSubject, ReplaySubject, and AsyncSubject?
- Subject - multicast Observable; no initial value; only emits to current subscribers.
- BehaviorSubject - requires initial value; emits current value to new subscribers immediately.
- ReplaySubject(n) - replays last n emissions to new subscribers.
- AsyncSubject - only emits the last value when the Observable completes.
const bs = new BehaviorSubject<number>(0);\nbs.subscribe(v => console.log("A:", v)); // A: 0\nbs.next(1); // A: 1\nbs.subscribe(v => console.log("B:", v)); // B: 1 (gets current value)
What are standalone components in Angular?
Standalone components (Angular 14+) do not need to be declared in an NgModule. They import their own dependencies directly. Angular 17+ makes standalone the default. Use bootstrapApplication() instead of AppModule.
@Component({\n standalone: true,\n imports: [CommonModule, RouterModule, FormsModule],\n template: `<h1>Hello</h1>`\n})\nexport class AppComponent {}
What is the difference between providedIn: "root" and providing in a module?
- providedIn: "root" - registers the service in the root injector; singleton across the entire app; tree-shakeable (removed if unused).
- Provided in NgModule providers[] - available only to that module and its components; not tree-shakeable.
- providedIn: "any" - creates a new instance for each lazy-loaded module.
What is the Angular HttpClient and how do you handle errors?
HttpClient provides methods for HTTP requests (get, post, put, delete). It returns Observables. Handle errors with catchError operator and throwError.
this.http.get<User[]>("/api/users").pipe(\n catchError(err => {\n console.error(err);\n return throwError(() => new Error("Failed to load users"));\n })\n).subscribe(users => this.users = users);
What is the difference between pure and impure pipes?
- Pure pipe (default) - only re-executes when the input reference changes. Efficient and cacheable.
- Impure pipe - re-executes on every change detection cycle regardless of input changes. Use sparingly (e.g., async pipe is impure).
@Pipe({ name: "filter", pure: false }) // impure\nexport class FilterPipe implements PipeTransform {\n transform(items: any[], term: string) {\n return items.filter(i => i.name.includes(term));\n }\n}
What is Zone.js and what is zoneless Angular?
Zone.js patches browser APIs (setTimeout, Promises, events) to notify Angular when async operations complete, triggering change detection. Zoneless Angular (Angular 18+) removes this dependency, using Signals for explicit change notification. Zoneless apps are faster and easier to debug.
What is the difference between ngIf and ngSwitch?
- *ngIf - conditionally adds/removes a single element from the DOM.
- *ngSwitch - conditionally renders one of multiple elements based on a value. Cleaner than multiple *ngIf for multi-case logic.
<div [ngSwitch]="status">\n <p *ngSwitchCase="'active'">Active</p>\n <p *ngSwitchCase="'inactive'">Inactive</p>\n <p *ngSwitchDefault>Unknown</p>\n</div>
What is the Angular @defer block?
@defer (Angular 17+) lazily loads a block of template content and its dependencies. Supports triggers: on idle, on viewport, on interaction, on hover, on timer, when condition. Replaces manual lazy loading patterns.
@defer (on viewport) {\n <app-heavy-chart />\n} @placeholder {\n <p>Loading chart...</p>\n} @loading (minimum 500ms) {\n <app-spinner />\n} @error {\n <p>Failed to load</p>\n}
What is the difference between @Input() and @Input({ required: true })?
@Input() marks a property as an input binding from a parent component. @Input({ required: true }) (Angular 16+) makes the input mandatory — Angular throws a compile-time error if the parent does not provide it, eliminating runtime undefined bugs.
@Component({ ... })\nexport class CardComponent {\n @Input({ required: true }) title!: string;\n @Input() subtitle = ""; // optional with default\n}
What is the Angular CDK and what does it provide?
The Angular Component Dev Kit (CDK) provides low-level primitives for building UI components: Overlay (popups, tooltips), DragDrop, VirtualScrolling, Accessibility (focus trap, live announcer), Portal, and Layout (breakpoint observer). It is the foundation of Angular Material.
What is the difference between ngOnChanges and ngDoCheck?
- ngOnChanges - called only when @Input() reference changes. Receives a SimpleChanges object with previous and current values. Not called for mutations inside objects/arrays.
- ngDoCheck - called on every change detection run. Use to detect mutations that ngOnChanges misses (e.g., array push). Expensive — use sparingly.
What is the Angular Resolver?
A Resolver pre-fetches data before a route is activated, ensuring the component has the data it needs on initialization. Modern Angular uses functional resolvers.
export const userResolver: ResolveFn<User> = (route) => {\n return inject(UserService).getUser(route.paramMap.get("id")!);\n};\n\n// Route config\n{ path: "user/:id", component: UserComponent, resolve: { user: userResolver } }
What is the difference between RouterModule.forRoot() and forChild()?
- forRoot() - registers the router with the root injector and sets up the router outlet. Called once in the root AppModule or via provideRouter().
- forChild() - registers additional routes for feature modules without re-registering the router service. Called in feature modules.
What is the takeUntilDestroyed operator?
takeUntilDestroyed (Angular 16+) automatically completes an Observable when the component is destroyed. It replaces the manual takeUntil + Subject pattern for unsubscribing.
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";\n\nexport class UserComponent {\n constructor() {\n this.userService.getUsers().pipe(\n takeUntilDestroyed() // auto-unsubscribes on destroy\n ).subscribe(users => this.users = users);\n }\n}
What is the difference between ElementRef, Renderer2, and direct DOM manipulation?
- ElementRef - provides direct access to the native DOM element. Avoid for security (XSS risk) and SSR compatibility.
- Renderer2 - abstraction layer for DOM manipulation. Works with SSR and Web Workers. Preferred approach.
- Direct DOM manipulation (document.querySelector) - bypasses Angular and breaks SSR.
constructor(private renderer: Renderer2, private el: ElementRef) {}\n\nngOnInit() {\n this.renderer.setStyle(this.el.nativeElement, "color", "red");\n}
What is the Angular TestBed?
TestBed is Angular's primary testing utility. It creates a testing module that mimics an NgModule, allowing you to test components, services, and pipes in isolation with dependency injection.
describe("UserComponent", () => {\n beforeEach(() => TestBed.configureTestingModule({\n imports: [UserComponent],\n providers: [{ provide: UserService, useValue: mockUserService }]\n }));\n\n it("should display name", () => {\n const fixture = TestBed.createComponent(UserComponent);\n fixture.detectChanges();\n expect(fixture.nativeElement.textContent).toContain("Alice");\n });\n});
What is the difference between @HostListener and @HostBinding?
- @HostListener - listens to events on the host element of a directive/component.
- @HostBinding - binds a property of the host element to a directive property.
@Directive({ selector: "[appHighlight]" })\nexport class HighlightDirective {\n @HostBinding("style.backgroundColor") bgColor = "";\n\n @HostListener("mouseenter") onEnter() { this.bgColor = "yellow"; }\n @HostListener("mouseleave") onLeave() { this.bgColor = ""; }\n}
What is the Angular inject() function?
inject() is a function-based alternative to constructor injection. It can be used in component/directive/pipe constructors, factory functions, and guards. It enables cleaner code and works in standalone contexts without constructor boilerplate.
@Component({ ... })\nexport class UserComponent {\n private userService = inject(UserService);\n private router = inject(Router);\n private route = inject(ActivatedRoute);\n}
What is the difference between ngModel and formControl?
- ngModel (template-driven) - two-way binding with [(ngModel)]. Requires FormsModule. State managed in template.
- formControl (reactive) - explicit FormControl instance in the component. Requires ReactiveFormsModule. State managed in component class. Easier to test and validate programmatically.
// Template-driven\n<input [(ngModel)]="username">\n\n// Reactive\n<input [formControl]="usernameControl">\nusernameControl = new FormControl("", Validators.required);
What is the Angular animation system?
Angular animations use the Web Animations API via @angular/animations. Define animations with trigger(), state(), transition(), animate(), and keyframes(). Import BrowserAnimationsModule or provideAnimations().
@Component({\n animations: [\n trigger("fadeIn", [\n transition(":enter", [\n style({ opacity: 0 }),\n animate("300ms ease-in", style({ opacity: 1 }))\n ])\n ])\n ]\n})\nexport class CardComponent {}
What is the difference between AOT and JIT compilation in Angular?
- JIT (Just-in-Time) - compiles templates in the browser at runtime. Slower startup, larger bundle. Used in development.
- AOT (Ahead-of-Time) - compiles templates at build time. Faster startup, smaller bundle, catches template errors early. Used in production (default since Angular 9).
What is the Angular HttpInterceptor?
Interceptors intercept HTTP requests and responses globally. Used for adding auth headers, logging, error handling, and loading indicators.
export const authInterceptor: HttpInterceptorFn = (req, next) => {\n const token = inject(AuthService).getToken();\n const authReq = req.clone({\n headers: req.headers.set("Authorization", `Bearer ${token}`)\n });\n return next(authReq);\n};
What is the difference between @NgModule and standalone components?
- @NgModule - groups components, directives, pipes, and providers. Required in Angular before v14. Adds boilerplate but provides clear boundaries.
- Standalone - components declare their own imports. No NgModule needed. Default in Angular 17+. Simpler, more tree-shakeable.
What is the Angular Router's ActivatedRoute?
ActivatedRoute provides information about the currently activated route: params, queryParams, data, fragment, and URL segments. Use snapshot for one-time reads or subscribe to the Observable for dynamic changes.
export class UserComponent {\n private route = inject(ActivatedRoute);\n\n ngOnInit() {\n // Snapshot (one-time)\n const id = this.route.snapshot.paramMap.get("id");\n\n // Observable (reacts to changes)\n this.route.paramMap.subscribe(params => {\n this.loadUser(params.get("id"));\n });\n }\n}
What is the difference between combineLatest, forkJoin, and zip in RxJS?
- forkJoin - waits for all Observables to complete, then emits the last values as an array. Best for parallel HTTP requests.
- combineLatest - emits whenever any Observable emits, combining latest values from all. Best for reactive UI state.
- zip - emits only when ALL Observables have emitted a new value, pairing them by index.
// Parallel HTTP requests\nforkJoin([this.api.getUser(), this.api.getPosts()])\n .subscribe(([user, posts]) => { ... });
What is the Angular FormArray?
FormArray manages a dynamic list of FormControls or FormGroups. Use it for forms with a variable number of fields (e.g., adding/removing phone numbers).
this.form = this.fb.group({\n phones: this.fb.array([\n this.fb.control("", Validators.required)\n ])\n});\n\nget phones() { return this.form.get("phones") as FormArray; }\n\naddPhone() {\n this.phones.push(this.fb.control(""));\n}
What is the difference between ViewEncapsulation.Emulated, None, and ShadowDom?
- Emulated (default) - Angular adds unique attributes to scope CSS to the component. No real Shadow DOM.
- None - styles are global. No encapsulation. Can affect other components.
- ShadowDom - uses native browser Shadow DOM. True style isolation. Limited browser support for some features.
@Component({\n encapsulation: ViewEncapsulation.None // global styles\n})
What is the Angular toSignal() and toObservable() function?
toSignal() converts an Observable to a Signal for use in signal-based components. toObservable() converts a Signal back to an Observable. Both are in @angular/core/rxjs-interop.
import { toSignal, toObservable } from "@angular/core/rxjs-interop";\n\nexport class UserComponent {\n users = toSignal(this.userService.getUsers(), { initialValue: [] });\n // users is now a Signal<User[]>, usable in templates without async pipe\n}
What is the difference between ngFor trackBy and default tracking?
By default, *ngFor tracks items by object identity — any change recreates all DOM elements. trackBy provides a function returning a unique identifier, so Angular only re-renders changed items. Critical for performance with large lists.
<li *ngFor="let user of users; trackBy: trackById">{{ user.name }}</li>\n\ntrackById(index: number, user: User): number {\n return user.id;\n}
What is the Angular environment configuration?
Angular uses environment files (environment.ts, environment.prod.ts) to store build-specific configuration like API URLs and feature flags. Angular CLI replaces the file at build time using fileReplacements in angular.json.
// environment.ts\nexport const environment = {\n production: false,\n apiUrl: "http://localhost:3000"\n};\n\n// Usage\nimport { environment } from "../environments/environment";\nthis.http.get(environment.apiUrl + "/users");
What is the difference between @Output() EventEmitter and Signals for parent-child communication?
- @Output() EventEmitter - child emits events that parent listens to with (event) binding. Traditional approach.
- Signal-based output() (Angular 17.3+) - uses output() function. More consistent with signal-based architecture.
- For deeply nested communication, prefer a shared service with BehaviorSubject or Signals.
// Traditional\n@Output() userSelected = new EventEmitter<User>();\n\n// Signal-based (Angular 17.3+)\nuserSelected = output<User>();
Level Up Your Angular Skills
Master Angular with these hand-picked resources