> ## Documentation Index
> Fetch the complete documentation index at: https://resources.devweekends.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 31. Interview Questions

> Comprehensive Angular interview preparation guide

![Interview Questions](https://mintcdn.com/devweeekends/AEOaWh79Ur7CdHHv/images/courses/angular-crash-course/angular-hero.svg?fit=max\&auto=format\&n=AEOaWh79Ur7CdHHv\&q=85\&s=32645ae19fa9bc25d3ec281022aba371)

## Interview Questions Overview

> [!NOTE]
>
> **Estimated Time**: 4 hours | **Difficulty**: All Levels | **Prerequisites**: Complete Angular Course

This comprehensive guide covers Angular interview questions from basic to advanced levels, helping you prepare for technical interviews at any stage of your career.

**How to use this guide**: Do not memorize answers -- interviewers can spot rehearsed responses immediately. Instead, understand the *why* behind each answer so you can reason through variations. A senior engineer would say: "I know the trade-offs and can explain when I would choose differently." That framing is worth more than any perfect textbook answer.

***

## Core Angular Concepts

### Q1: What is Angular and how does it differ from AngularJS?

> **Answer**
>
> **Angular** is a TypeScript-based platform for building web applications, completely rewritten from AngularJS.
>
> Key differences:
>
> * **Architecture**: Angular uses component-based architecture; AngularJS uses MVC
> * **Language**: Angular uses TypeScript; AngularJS uses JavaScript
> * **Mobile**: Angular supports mobile development; AngularJS doesn't
> * **Performance**: Angular has improved change detection and AOT compilation
> * **CLI**: Angular has powerful CLI; AngularJS doesn't have official CLI

### Q2: Explain the Angular component lifecycle hooks

> **Answer**
>
> ```typescript theme={null}
> @Component({...})
> export class ExampleComponent implements OnInit, OnChanges, OnDestroy {
>   // Called once before ngOnInit when inputs change
>   ngOnChanges(changes: SimpleChanges) {}
>
>   // Called once after first ngOnChanges
>   ngOnInit() {}
>
>   // Called every change detection cycle
>   ngDoCheck() {}
>
>   // Called once after first ngDoCheck
>   ngAfterContentInit() {}
>
>   // Called after every ngDoCheck
>   ngAfterContentChecked() {}
>
>   // Called once after first ngAfterContentChecked
>   ngAfterViewInit() {}
>
>   // Called after every ngAfterContentChecked
>   ngAfterViewChecked() {}
>
>   // Called before component is destroyed
>   ngOnDestroy() {}
> }
> ```
>
> **Order**: constructor → ngOnChanges → ngOnInit → ngDoCheck → ngAfterContentInit → ngAfterContentChecked → ngAfterViewInit → ngAfterViewChecked → ngOnDestroy

### Q3: What are Angular Signals?

> **Answer**
>
> Signals are a reactive primitive introduced in Angular 16 for fine-grained reactivity.
>
> ```typescript theme={null}
> // Creating signals
> const count = signal(0);
> const name = signal('Angular');
>
> // Reading signals
> console.log(count()); // 0
>
> // Updating signals
> count.set(5);
> count.update(v => v + 1);
>
> // Computed signals (derived values)
> const doubled = computed(() => count() * 2);
>
> // Effects (side effects)
> effect(() => {
>   console.log(`Count is: ${count()}`);
> });
> ```
>
> **Benefits**:
>
> * Fine-grained reactivity (only affected components update)
> * Better performance than Zone.js change detection
> * Simpler mental model than RxJS for synchronous state
> * Lazy evaluation of computed values (only recompute when read AND dependencies changed)
>
> **What a senior engineer would add**: "Signals are not a replacement for RxJS -- they solve different problems. Signals are for synchronous, UI-driven state (a counter, a filter value, a selected item). RxJS is for asynchronous streams (HTTP responses, WebSocket messages, debounced user input). The best Angular codebases use both: signals for component state, RxJS for async pipelines, and `toSignal()` / `toObservable()` as bridges between them."

### Q4: Explain the difference between OnPush and Default change detection

> **Answer**
>
> **Default Strategy**: Angular checks the entire component tree on every change detection cycle.
>
> **OnPush Strategy**: Component only checked when:
>
> 1. Input reference changes
> 2. Event from component or child
> 3. Async pipe emits new value
> 4. Manual `markForCheck()` or `detectChanges()`
>
> ```typescript theme={null}
> @Component({
>   changeDetection: ChangeDetectionStrategy.OnPush
> })
> export class OptimizedComponent {
>   data = input<Data>(); // Only triggers on reference change
>
>   // Manual trigger if needed
>   private cdr = inject(ChangeDetectorRef);
>
>   forceUpdate() {
>     this.cdr.markForCheck();
>   }
> }
> ```
>
> **Best Practice**: Use OnPush everywhere with immutable data patterns.
>
> **Interview tip**: If asked "when would you NOT use OnPush?", the honest answer is "almost never in new code." The only exception is rapid prototyping where you are mutating objects in place and do not want to debug why the UI is not updating. But any production code should use OnPush -- it turns change detection from "check everything every time" to "check this component only when its inputs change." That is the difference between O(n) and O(1) per component.

***

## Dependency Injection

### Q5: What is Dependency Injection and how does Angular implement it?

> **Answer**
>
> DI is a design pattern where dependencies are provided to a class rather than created by it.
>
> ```typescript theme={null}
> // Service definition
> @Injectable({ providedIn: 'root' })
> export class UserService {
>   getUser(id: string): Observable<User> { ... }
> }
>
> // Injection in component
> @Component({...})
> export class UserComponent {
>   private userService = inject(UserService);
>
>   // Or via constructor
>   constructor(private userService: UserService) {}
> }
> ```
>
> **Hierarchical Injector**:
>
> * Root level: `providedIn: 'root'` (singleton)
> * Module level: `providers` array in NgModule
> * Component level: `providers` in component (new instance per component)
>
> **Benefits**: Loose coupling, testability, reusability

### Q6: Explain providedIn options

> **Answer**
>
> ```typescript theme={null}
> // Singleton for entire app
> @Injectable({ providedIn: 'root' })
>
> // Singleton per lazy-loaded module
> @Injectable({ providedIn: 'any' })
>
> // Provided to specific module
> @Injectable({ providedIn: SomeModule })
>
> // Platform level (shared across apps)
> @Injectable({ providedIn: 'platform' })
>
> // Not automatically provided (must add to providers array)
> @Injectable()
> ```

***

## Templates & Data Binding

### Q7: Explain the different types of data binding in Angular

> **Answer**
>
> ```html theme={null}
> <!-- 1. Interpolation (one-way) -->
> <p>{{ message }}</p>
>
> <!-- 2. Property Binding (one-way) -->
> <img [src]="imageUrl">
> <button [disabled]="isDisabled">
>
> <!-- 3. Event Binding (one-way) -->
> <button (click)="onClick()">
>
> <!-- 4. Two-way Binding -->
> <input [(ngModel)]="name">
> <!-- Equivalent to: -->
> <input [ngModel]="name" (ngModelChange)="name = $event">
>
> <!-- 5. Attribute Binding -->
> <td [attr.colspan]="colSpan">
>
> <!-- 6. Class Binding -->
> <div [class.active]="isActive">
>
> <!-- 7. Style Binding -->
> <div [style.color]="textColor">
> ```

### Q8: What is the difference between ng-template, ng-container, and ng-content?

> **Answer**
>
> **ng-template**: Defines a template that is not rendered by default
>
> ```html theme={null}
> <ng-template #myTemplate let-name="name">
>   <p>Hello, {{ name }}</p>
> </ng-template>
> <ng-container *ngTemplateOutlet="myTemplate; context: {name: 'Angular'}"/>
> ```
>
> **ng-container**: Logical grouping without adding extra DOM elements
>
> ```html theme={null}
> <ng-container *ngIf="condition">
>   <p>No wrapper element added</p>
> </ng-container>
> ```
>
> **ng-content**: Content projection (transclusion)
>
> ```html theme={null}
> <!-- parent-component.html -->
> <child-component>
>   <p>This content is projected</p>
> </child-component>
>
> <!-- child-component.html -->
> <div class="wrapper">
>   <ng-content></ng-content>
> </div>
> ```

***

## Routing

### Q9: What are Route Guards and their types?

> **Answer**
>
> ```typescript theme={null}
> // CanActivate - Control access to route
> export const authGuard: CanActivateFn = (route, state) => {
>   const auth = inject(AuthService);
>   return auth.isLoggedIn() ? true : inject(Router).createUrlTree(['/login']);
> };
>
> // CanActivateChild - Control access to child routes
> export const adminGuard: CanActivateChildFn = () => {
>   return inject(AuthService).isAdmin();
> };
>
> // CanDeactivate - Prevent leaving route
> export const unsavedChangesGuard: CanDeactivateFn<HasUnsavedChanges> = (component) => {
>   return component.hasUnsavedChanges() 
>     ? confirm('Discard changes?') 
>     : true;
> };
>
> // CanMatch - Prevent route matching entirely
> export const featureGuard: CanMatchFn = () => {
>   return inject(FeatureService).isEnabled('new-feature');
> };
>
> // Resolve - Pre-fetch data before activation
> export const userResolver: ResolveFn<User> = (route) => {
>   return inject(UserService).getUser(route.params['id']);
> };
>
> // Routes configuration
> const routes: Routes = [
>   {
>     path: 'admin',
>     canActivate: [authGuard],
>     canActivateChild: [adminGuard],
>     canMatch: [featureGuard],
>     children: [...]
>   }
> ];
> ```

### Q10: Explain lazy loading in Angular

> **Answer**
>
> ```typescript theme={null}
> // Lazy load routes
> const routes: Routes = [
>   {
>     path: 'products',
>     loadChildren: () => import('./products/products.routes')
>       .then(m => m.PRODUCTS_ROUTES)
>   },
>   {
>     path: 'admin',
>     loadComponent: () => import('./admin/admin.component')
>       .then(m => m.AdminComponent)
>   }
> ];
>
> // Preloading strategies
> @NgModule({
>   imports: [
>     RouterModule.forRoot(routes, {
>       preloadingStrategy: PreloadAllModules
>       // Or custom: CustomPreloadingStrategy
>     })
>   ]
> })
>
> // Deferrable views (Angular 17+)
> @defer (on viewport) {
>   <app-heavy-component />
> } @placeholder {
>   <app-skeleton />
> }
> ```

***

## RxJS & HTTP

### Q11: What is the difference between Subject, BehaviorSubject, and ReplaySubject?

This is one of the most frequently asked RxJS questions. The key mental model: all Subjects are both Observables (you can subscribe to them) and Observers (you can push values into them). They differ in what happens to **late subscribers** -- subscribers that join after values have already been emitted.

> **Answer**
>
> ```typescript theme={null}
> // Subject - No initial value, late subscribers miss past emissions
> const subject = new Subject<number>();
> subject.next(1);
> subject.subscribe(v => console.log(v)); // Won't receive 1
> subject.next(2); // Logs: 2
>
> // BehaviorSubject - Has initial/current value
> const behavior = new BehaviorSubject<number>(0);
> behavior.next(1);
> behavior.subscribe(v => console.log(v)); // Logs: 1 (current value)
> behavior.getValue(); // Returns current value: 1
>
> // ReplaySubject - Replays N values to new subscribers
> const replay = new ReplaySubject<number>(2); // Buffer size 2
> replay.next(1);
> replay.next(2);
> replay.next(3);
> replay.subscribe(v => console.log(v)); // Logs: 2, 3
>
> // AsyncSubject - Only emits last value on completion
> const async = new AsyncSubject<number>();
> async.next(1);
> async.next(2);
> async.subscribe(v => console.log(v)); // Nothing yet
> async.complete(); // Now logs: 2
> ```

### Q12: Explain common RxJS operators

The trick to mastering RxJS operators is to group them by *what problem they solve*, not memorize them alphabetically. In an interview, showing you can pick the right operator for a scenario is far more impressive than listing 20 operator names.

> **Answer**
>
> ```typescript theme={null}
> // Transformation
> map(x => x * 2)              // Transform each value
> switchMap(x => http.get(x))  // Switch to new observable, cancel previous
> mergeMap(x => http.get(x))   // Merge all inner observables
> concatMap(x => http.get(x))  // Queue inner observables sequentially
>
> // Filtering
> filter(x => x > 0)           // Filter values
> distinctUntilChanged()       // Only emit when value changes
> debounceTime(300)            // Wait for pause in emissions
> throttleTime(300)            // Rate limit emissions
> take(5)                      // Take first N values
> takeUntil(destroy$)          // Take until signal
>
> // Combination
> combineLatest([a$, b$])      // Emit when any source emits
> forkJoin([a$, b$])           // Emit when all complete
> merge(a$, b$)                // Merge multiple streams
> withLatestFrom(other$)       // Combine with latest from another
>
> // Error Handling
> catchError(err => of(null))  // Handle errors
> retry(3)                     // Retry on error
> retryWhen(...)               // Custom retry logic
>
> // Utility
> tap(x => console.log(x))     // Side effects
> shareReplay(1)               // Share and cache last value
> ```

***

## Testing

### Q13: How do you test Angular components?

> **Answer**
>
> ```typescript theme={null}
> describe('UserComponent', () => {
>   let component: UserComponent;
>   let fixture: ComponentFixture<UserComponent>;
>   let userServiceSpy: jasmine.SpyObj<UserService>;
>
>   beforeEach(async () => {
>     userServiceSpy = jasmine.createSpyObj('UserService', ['getUser']);
>     userServiceSpy.getUser.and.returnValue(of({ id: '1', name: 'Test' }));
>
>     await TestBed.configureTestingModule({
>       imports: [UserComponent],
>       providers: [
>         { provide: UserService, useValue: userServiceSpy }
>       ]
>     }).compileComponents();
>
>     fixture = TestBed.createComponent(UserComponent);
>     component = fixture.componentInstance;
>   });
>
>   it('should create', () => {
>     expect(component).toBeTruthy();
>   });
>
>   it('should display user name', () => {
>     fixture.componentRef.setInput('userId', '1');
>     fixture.detectChanges();
>
>     const nameElement = fixture.nativeElement.querySelector('.user-name');
>     expect(nameElement.textContent).toContain('Test');
>   });
>
>   it('should call service on init', () => {
>     fixture.componentRef.setInput('userId', '1');
>     fixture.detectChanges();
>
>     expect(userServiceSpy.getUser).toHaveBeenCalledWith('1');
>   });
> });
> ```

***

## Performance

### Q14: How do you optimize Angular application performance?

> **Answer**
>
> **Build-time optimizations:**
>
> * AOT compilation
> * Tree shaking
> * Code splitting / lazy loading
> * Bundle analysis and optimization
>
> **Runtime optimizations:**
>
> ```typescript theme={null}
> // 1. OnPush change detection
> @Component({
>   changeDetection: ChangeDetectionStrategy.OnPush
> })
>
> // 2. TrackBy for lists
> @for (item of items(); track item.id) {
>   <app-item [item]="item" />
> }
>
> // 3. Signals for reactive state
> count = signal(0);
> doubled = computed(() => this.count() * 2);
>
> // 4. Deferrable views
> @defer (on viewport) {
>   <heavy-component />
> }
>
> // 5. Virtual scrolling for large lists
> <cdk-virtual-scroll-viewport itemSize="50">
>   <div *cdkVirtualFor="let item of items">{{ item }}</div>
> </cdk-virtual-scroll-viewport>
>
> // 6. Pure pipes
> @Pipe({ pure: true })
>
> // 7. Unsubscribe properly
> takeUntilDestroyed(this.destroyRef)
> ```

***

## Advanced Topics

### Q15: What is Zone.js and how does Angular use it?

> **Answer**
>
> Zone.js is a library that patches async APIs (setTimeout, Promise, XHR, etc.) to notify Angular when async operations complete.
>
> ```typescript theme={null}
> // Zone.js patches these to trigger change detection:
> setTimeout(() => {})
> Promise.resolve().then(() => {})
> fetch('/api').then(() => {})
> element.addEventListener('click', () => {})
>
> // Running outside Angular zone (for performance)
> @Component({...})
> export class PerformanceComponent {
>   private ngZone = inject(NgZone);
>
>   heavyOperation() {
>     this.ngZone.runOutsideAngular(() => {
>       // This won't trigger change detection
>       setInterval(() => this.trackMouse(), 10);
>     });
>   }
>
>   updateUI() {
>     this.ngZone.run(() => {
>       // This triggers change detection
>       this.value = 'updated';
>     });
>   }
> }
> ```
>
> **Zoneless Angular (experimental in v18)**:
>
> ```typescript theme={null}
> bootstrapApplication(App, {
>   providers: [
>     provideExperimentalZonelessChangeDetection()
>   ]
> });
> ```

### Q16: Explain Angular SSR and Hydration

> **Answer**
>
> **Server-Side Rendering (SSR)** renders the application on the server, sending HTML to the client.
>
> **Hydration** reuses the server-rendered DOM instead of re-creating it.
>
> ```typescript theme={null}
> // app.config.server.ts
> export const config: ApplicationConfig = {
>   providers: [
>     provideServerRendering(),
>     provideClientHydration()
>   ]
> };
>
> // Benefits:
> // - Better SEO (search engines see content)
> // - Faster First Contentful Paint
> // - Better Core Web Vitals
> // - Works with JavaScript disabled
>
> // Hydration skipping for dynamic content
> @Component({
>   host: { ngSkipHydration: 'true' }
> })
> export class DynamicComponent {}
> ```

***

## Coding Challenges

### Challenge 1: Implement a debounced search

> **Solution**
>
> ```typescript theme={null}
> @Component({
>   template: `
>     <input [formControl]="searchControl" placeholder="Search...">
>     @for (result of results(); track result.id) {
>       <div>{{ result.name }}</div>
>     }
>   `
> })
> export class SearchComponent {
>   private searchService = inject(SearchService);
>   private destroyRef = inject(DestroyRef);
>
>   searchControl = new FormControl('');
>   results = signal<SearchResult[]>([]);
>
>   ngOnInit() {
>     this.searchControl.valueChanges.pipe(
>       debounceTime(300),
>       distinctUntilChanged(),
>       filter(term => term.length >= 2),
>       switchMap(term => this.searchService.search(term)),
>       takeUntilDestroyed(this.destroyRef)
>     ).subscribe(results => this.results.set(results));
>   }
> }
> ```

### Challenge 2: Create a reusable modal service

> **Solution**
>
> ```typescript theme={null}
> @Injectable({ providedIn: 'root' })
> export class ModalService {
>   private vcr!: ViewContainerRef;
>
>   setContainer(vcr: ViewContainerRef) {
>     this.vcr = vcr;
>   }
>
>   open<T, R>(component: Type<T>, data?: Partial<T>): Observable<R> {
>     const subject = new Subject<R>();
>     const ref = this.vcr.createComponent(component);
>
>     if (data) {
>       Object.entries(data).forEach(([key, value]) => {
>         ref.setInput(key, value);
>       });
>     }
>
>     // Assuming component has 'closed' output
>     ref.instance.closed?.subscribe((result: R) => {
>       subject.next(result);
>       subject.complete();
>       ref.destroy();
>     });
>
>     return subject.asObservable();
>   }
> }
> ```

***

## Tips for Success

> **Understand Fundamentals**
>
> Know DI, change detection, and component lifecycle deeply

> **Practice Coding**
>
> Be ready to write code on whiteboard or shared editor

> **Know RxJS**
>
> Understand operators and when to use them

> **Discuss Trade-offs**
>
> Show you can evaluate different approaches

***

> **[Next: Best Practices](https://resources.devweekends.com/courses/angular-crash-course/32-best-practices.md)**
>
> Learn Angular best practices and style guide


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.