Angular Interview QA

What is Angular?

Angular is a TypeScript-based frontend framework developed by Google. It is used to build single-page applications (SPA) that are fast, modular, and maintainable.

Angular provides:

  • High performance: Efficient change detection and rendering
  • Modular architecture: Components, modules, services
  • Strong tooling: CLI, testing utilities, and debugging tools
  • Two-way data binding: Synchronizes data between model and view
  • Reactive programming support: Observables and RxJS

It is widely used for enterprise applications, dashboards, and dynamic web apps that require fast updates and rich user experiences.

Architecture of Angular

Angular follows a Component-Based Architecture, which makes applications modular, maintainable, and scalable.

✅ Main Building Blocks of Angular

  • Modules (NgModule): Organize the app into cohesive blocks of functionality.
  • Components: Define views, templates, and logic for UI elements.
  • Templates (HTML): Define the structure and layout of the UI.
  • Directives: Modify the DOM structure or behavior of elements.
  • Services: Handle business logic, data fetching, and reusable operations.
  • Dependency Injection (DI): Provides services to components efficiently.
  • Routing: Navigate between views in a single-page application.
  • Pipes: Transform data in templates.

📌 Simple Architecture Flow

User interactions are handled in a predictable flow:

User Action → Component → Service → API → Data → Template UI Update

Example Flow:

  • User clicks a button
  • Component calls a service
  • Service calls an API using HttpClient
  • API responds with data
  • Component updates the UI template

This architecture ensures separation of concerns, modularity, and easier maintenance for large-scale applications.

Components in Angular

A Component is the main UI building block in Angular. Each component encapsulates its own:

  • HTML template: Defines the view of the component
  • TypeScript logic: The class controlling behavior
  • CSS styles: Defines the look and feel

Key Points About Components

  • ✅ Each component controls a part of the screen
  • ✅ Angular apps are built by combining multiple components
  • ✅ Components are reusable
@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.css']
})
export class UserComponent {
  name: string = 'John Doe';
}

Modules in Angular

A Module is a container that groups related:

  • Components
  • Directives
  • Pipes
  • Services

Angular uses modules to organize the application into logical blocks and improve maintainability.

Types of Modules

  • Root Module: AppModule – Bootstraps the application
  • Feature Module: InvoiceModule, AdminModule – Encapsulates a specific feature
  • Shared Module: Contains common components, pipes, directives used across the app
  • Core Module: Contains singleton services and app-wide providers
@NgModule({
  declarations: [UserComponent],
  imports: [CommonModule],
  exports: [UserComponent]
})
export class SharedModule {}

Data Binding in Angular

Data Binding is the communication between:

  • Component (TypeScript)
  • Template (HTML)
It keeps the UI and data in sync automatically.

Types of Data Binding

1️⃣ Interpolation (One-way: TS → HTML)

Hello {{ name }}

2️⃣ Property Binding (One-way: TS → HTML)



3️⃣ Event Binding (One-way: HTML → TS)


4️⃣ Two-Way Binding (TS ↔ HTML)


You typed: {{ username }}

Summary Table of Data Binding

Binding Type Direction Example
Interpolation TS → HTML {{name}}
Property Binding TS → HTML [value]="data"
Event Binding HTML → TS (click)="do()"
Two-way Binding Both [(ngModel)]="name"

Difference Between Component and Directive

✅ Component

  • A component is a directive with a template
  • Used to build UI blocks (header, login, dashboard)
  • Has:
    • HTML template
    • CSS styles
    • TypeScript logic

✅ Directive

  • A directive does not have its own UI template
  • Used to change behavior or appearance of an element
  • Example: ngIf, ngFor, ngClass

Feature Comparison Table

Feature Component Directive
Template ✅ Yes ❌ No
Purpose UI block Modify behavior/style
Example Navbar, Login Highlight, Hide, Validation

Angular Pipes

In Angular, Pipes are used to transform data before displaying it in the template. Pipes take input data, process it, and return a formatted output. They help keep templates clean, readable, and maintainable.


What is a Pipe in Angular?

A Pipe in Angular is a simple way to transform values such as strings, dates, numbers, or asynchronous data directly in the template.

{{ expression | pipeName }}

Why Use Pipes?

  • Improve code readability
  • Reuse transformation logic
  • Keep component logic clean
  • Format data directly in templates

Types of Pipes in Angular (By Origin)

Angular provides two main types of pipes:

1. Built-in Pipes

These pipes are provided by Angular out of the box.

  • DatePipe – Formats date values
  • UpperCasePipe – Converts text to uppercase
  • LowerCasePipe – Converts text to lowercase
  • TitleCasePipe – Converts text to title case
  • CurrencyPipe – Formats currency values
  • DecimalPipe – Formats decimal numbers
  • PercentPipe – Formats percentages
  • SlicePipe – Extracts a subset of a string or array
  • JsonPipe – Converts objects into JSON format
  • AsyncPipe – Handles Observables and Promises

2. Custom Pipes

Custom pipes are created by developers to perform application-specific data transformations using the @Pipe decorator.

Creating a Custom Pipe in Angular

Custom pipes allow you to create reusable data transformation logic based on your application needs.

Steps to Create a Custom Pipe

  1. Create a pipe using CLI: ng generate pipe pipeName or manually
  2. Implement the PipeTransform interface
  3. Define the transform() method
  4. Return the transformed data

@Pipe({ name: 'customPipe' })
export class CustomPipe implements PipeTransform {
  transform(value: any): any {
    return value;
  }
}

Example: Filter Array of Strings

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({ name: 'filter' })
export class FilterPipe implements PipeTransform {
  transform(items: string[], searchText: string): string[] {
    if (!items || !searchText) return items;
    return items.filter(item =>
      item.toLowerCase().includes(searchText.toLowerCase())
    );
  }
}

Usage

<li *ngFor="let name of names | filter:search">
  {{ name }}
</li>

Example: Reverse a String

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({ name: 'reverse' })
export class ReversePipe implements PipeTransform {
  transform(value: string): string {
    return value.split('').reverse().join('');
  }
}

Usage

<p>{{ 'Angular' | reverse }}</p>
<!-- Output: ralugnA -->

Example: Capitalize First Letter

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({ name: 'capitalize' })
export class CapitalizePipe implements PipeTransform {
  transform(value: string): string {
    return value.charAt(0).toUpperCase() +
           value.slice(1).toLowerCase();
  }
}

Usage

<p>{{ 'hello world' | capitalize }}</p>
<!-- Output: Hello world -->

Example: Email Validation Pipe

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({ name: 'emailCheck' })
export class EmailCheckPipe implements PipeTransform {
  transform(value: string): boolean {
    if (!value) return false;

    const emailRegex =
      /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;

    return emailRegex.test(value);
  }
}

Usage

<p>Valid Email: {{ email | emailCheck }}</p>

Usage with *ngIf

<p *ngIf="email | emailCheck; else invalid">
  Email is valid
</p>

<ng-template #invalid>
  Email is invalid
</ng-template>

Async Pipe in Angular

The AsyncPipe is a built-in Angular pipe used to handle asynchronous data streams such as Observables and Promises.

  • Automatically subscribes to data
  • Automatically unsubscribes on component destroy
  • Prevents memory leaks
{{ users$ | async }}

Pipe Chaining in Angular

Pipe Chaining allows multiple pipes to be applied sequentially. The output of one pipe becomes the input of the next pipe.

{{ today | date:'fullDate' | uppercase }}

Pipe chaining is a usage concept, not a separate type of pipe.


Types of Pipes by Behavior

Angular pipes can also be classified based on how they respond to change detection.

Pure Pipes

  • Default behavior
  • Executed only when input value changes
  • Better performance

Examples: DatePipe, UpperCasePipe, DecimalPipe

Impure Pipes

  • Executed on every change detection cycle
  • Lower performance
  • Used when data mutates without reference change
@Pipe({
  name: 'impurePipe',
  pure: false
})

AsyncPipe is an example of a built-in impure pipe.


Complete Classification of Angular Pipes

Concept Category
Built-in Pipe By Origin
Custom Pipe By Origin
Pure Pipe By Behavior
Impure Pipe By Behavior
AsyncPipe Built-in + Impure
Pipe Chaining Template Usage Concept

Conclusion

Angular Pipes provide a powerful and clean way to format and transform data directly in templates. Understanding built-in pipes, custom pipes, async pipe, pure vs impure behavior, and pipe chaining helps in writing efficient and maintainable Angular applications.

Important Notes

  • Custom pipes are pure by default
  • Use impure pipes carefully due to performance impact
  • Avoid heavy logic inside pipes
  • Pipes are best suited for formatting and transformation

Summary

  • Custom pipes allow reusable data transformation
  • They are easy to create and use in templates
  • Common examples include filtering, formatting, validation
  • Email validation can also be handled using custom pipes

Custom pipes in Angular are used to create reusable transformation logic that formats or modifies data directly in templates.

What is an Observable?

An Observable is a stream of data that can emit multiple values over time. To receive the emitted values, you must subscribe to it.

Key Characteristics of Observables

  • Supports multiple values
    An Observable can emit zero, one, or many values over time.
  • Lazy execution
    An Observable starts executing only when someone subscribes to it.
  • Can be canceled (unsubscribed)
    You can stop receiving data by unsubscribing, which helps prevent memory leaks.

Example of an Observable

import { Observable } from 'rxjs';

const observable = new Observable(observer => {
  observer.next('Hello');
  observer.next('World');
});

Observable in Angular Templates

In Angular templates, Observables are commonly used with the AsyncPipe, which automatically subscribes and unsubscribes.

{{ data$ | async }}

What is a Promise?

A Promise represents a single asynchronous result that may succeed (resolve) or fail (reject) in the future. Once resolved or rejected, a Promise cannot emit another value.

Use Cases of Promise

  • HTTP requests (older JavaScript/TypeScript code)
  • Async tasks such as file reading, timers, or API calls
  • When only one result is required

Example of a Promise

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('Data loaded');
  }, 1000);
});

promise.then(result => console.log(result));
       .catch(err => console.error(err));

Difference Between Observable and Promise

Feature Observable Promise
Values Can emit multiple values over time Emits a single value
Lazy / Eager Lazy (executes only on subscription) Eager (executes immediately)
Cancelable Yes, can unsubscribe No, cannot cancel
Operators Supports RxJS operators (map, filter, debounce) No operators
Use Case Real-time data, streams, events, WebSockets Single async operation

A Promise handles a single asynchronous value, while an Observable can emit multiple values over time and supports cancellation and powerful operators.

What are Directives in Angular?

Directives are special classes in Angular that are used to manipulate the DOM. They can change the appearance, behavior, or structure of elements in a template.

Directives do not render their own view; instead, they modify the behavior or structure of existing DOM elements.


Types of Directives in Angular

1. Structural Directives

Structural directives change the DOM structure by adding or removing elements. They are prefixed with an asterisk (*) in templates.

Examples of Structural Directives

  • *ngIf – Conditionally renders elements
  • *ngFor – Iterates over a list of items
  • *ngSwitch – Displays elements based on switch cases

Example

<div *ngIf="isLoggedIn">Welcome User</div>

<li *ngFor="let item of items">{{ item }}</li>

2. Attribute Directives

Attribute directives change the appearance or behavior of an element without changing the DOM structure.

Examples of Attribute Directives

  • ngClass – Dynamically add or remove CSS classes
  • ngStyle – Dynamically change inline styles
  • Custom Attribute Directives

Example

<div [ngClass]="{'active': isActive}">Active Item</div>

<div [ngStyle]="{'color': 'red'}">Styled Text</div>

Custom Attribute Directive Example

Below is an example of a custom attribute directive that highlights an element when the mouse enters and removes the highlight when the mouse leaves.

import { Directive, ElementRef, Renderer2, HostListener } from '@angular/core';

@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective {

  constructor(
    private el: ElementRef,
    private renderer: Renderer2
  ) {}

  @HostListener('mouseenter')
  onMouseEnter() {
    this.renderer.setStyle(
      this.el.nativeElement,
      'background-color',
      'yellow'
    );
  }

  @HostListener('mouseleave')
  onMouseLeave() {
    this.renderer.setStyle(
      this.el.nativeElement,
      'background-color',
      'white'
    );
  }
}

Usage

<p appHighlight>Hover over me</p>

Summary

  • Directives manipulate the DOM in Angular
  • Structural directives modify DOM structure
  • Attribute directives modify appearance or behavior
  • Custom directives allow reusable DOM behavior

@Input() and @Output() in Angular

✅ @Input()

Used to receive data from parent → child component.

Parent Component:

<app-child [name]="userName"></app-child>

Child Component:

import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-child',
  template: '<p>Hello {{ name }}</p>'
})
export class ChildComponent {
  @Input() name!: string;
}

✅ @Output()

Used to send data/events from child → parent component.

Child Component:

import { Component, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-child',
  template: '<button (click)="send()">Send</button>'
})
export class ChildComponent {
  @Output() notify = new EventEmitter<string>();

  send() {
    this.notify.emit("Hello Parent!");
  }
}

Parent Component:

<app-child (notify)="getMessage($event)"></app-child>

Difference Between Pure and Impure Pipes

✅ Pure Pipe (default)

  • Runs only when input reference changes
  • Faster and best for performance
@Pipe({ name: 'myPipe', pure: true })

✅ Impure Pipe

  • Runs on every change detection
  • Slower, use only when needed
@Pipe({ name: 'myPipe', pure: false })

🔥 Key Difference

Feature Pure Pipe Impure Pipe
Execution Only when value changes Every change detection
Performance ✅ Fast ❌ Slower
Use case Formatting, filtering stable data Filtering dynamic/mutating arrays

Dependency Injection (DI) in Angular

Dependency Injection is a design pattern where Angular automatically provides required objects (services) instead of creating them manually using new.

Example

constructor(private userService: UserService) {}

✅ Benefits of DI

  • Reusability
  • Loose coupling
  • Easy testing
  • Clean architecture

Different Ways to Provide a Service in Angular

1️⃣ Using providedIn: 'root'

@Injectable({ providedIn: 'root' })
export class UserService {}

2️⃣ Provide in AppModule

@NgModule({
  providers: [UserService]
})
export class AppModule {}

3️⃣ Provide in a Feature Module

@NgModule({
  providers: [UserService]
})
export class AdminModule {}

4️⃣ Provide in a Component

@Component({
  providers: [UserService]
})
export class DashboardComponent {}

Difference Between providedIn: 'root' and providers Array

  • providedIn: 'root'
    • Singleton service across the entire app
    • Tree-shakable (unused services removed during build)
    • Recommended approach
  • providers array
    • Can create multiple instances depending on where you provide it:
      • AppModule → singleton
      • Feature Module → scoped
      • Component → new instance per component

Angular Routing

Angular Routing allows navigation between different views/pages without reloading the page (SPA).

Example

const routes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: 'login', component: LoginComponent }
];

Lazy Loading

Lazy Loading means loading feature modules only when required, instead of loading everything at app start.

✅ Benefits

  • Faster initial load
  • Better performance
  • Smaller bundle size

Example

const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () =>
      import('./admin/admin.module').then(m => m.AdminModule)
  }
];

Difference Between RouterModule.forRoot() and RouterModule.forChild()

✅ forRoot()

  • Used only once in the root module (AppModule)
  • Creates the main router service
  • Registers app-level routes
  • RouterModule.forRoot(routes)

✅ forChild()

  • Used in feature modules
  • Adds additional routes to the router
  • Used in lazy-loaded modules
  • RouterModule.forChild(adminRoutes)

🔥 Key Difference Table

Feature forRoot() forChild()
Used in AppModule Feature Module
Router service Creates it Uses existing
Times used Only once Many times

ViewEncapsulation in Angular

ViewEncapsulation controls how Angular applies CSS styles to components. By default, Angular scopes component styles to that component only, not globally.

Types of ViewEncapsulation

1️⃣ Emulated (Default)

  • Styles apply only to that component
  • Angular adds unique attributes like _ngcontent-xxx
  • encapsulation: ViewEncapsulation.Emulated
  • ✅ Most commonly used

2️⃣ None

  • Styles become global
  • Can affect other components too
  • encapsulation: ViewEncapsulation.None
  • Use for global styling (rare)

3️⃣ ShadowDom

  • Uses real browser Shadow DOM
  • Styles are strictly isolated
  • encapsulation: ViewEncapsulation.ShadowDom
  • Use when true Shadow DOM behavior is needed

Guards in Angular

Guards control access to routes and decide whether navigation should be allowed or blocked.

Common Guard Types

  • CanActivate: Allow/deny entering a route
  • CanDeactivate: Allow/deny leaving a route
  • CanLoad: Allow/deny lazy-loaded module loading
  • Resolve: Fetch data before route loads

Example: CanActivate Guard

@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
  constructor(private router: Router) {}

  canActivate(): boolean {
    const isLoggedIn = !!localStorage.getItem("token");
    if (!isLoggedIn) {
      this.router.navigate(['/login']);
      return false;
    }
    return true;
  }
}

Usage:

{ path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] }

HttpClient in Angular

Angular’s HttpClient is a built-in service to call APIs. Import it via: import { HttpClientModule } from '@angular/common/http';

Key Points

  • ✅ Returns an Observable
  • ✅ Supports GET, POST, PUT, DELETE
  • ✅ Supports interceptors, headers, and error handling
  • ✅ Works with RxJS operators like map, catchError, retry

Example: GET API call

constructor(private http: HttpClient) {}

getUsers() {
  return this.http.get<User[]>("https://api.com/users");
}

// Component usage
this.getUsers().subscribe(data => {
  console.log(data);
});

How it Works Internally

  1. Component calls service method
  2. Service uses HttpClient
  3. HttpClient sends request through interceptors
  4. Server responds
  5. Observable emits response
  6. Component receives it via subscribe or async pipe

RxJS Subjects in Angular

1️⃣ Subject

  • Does NOT store old values
  • Subscribers receive values only after subscribing
import { Subject } from 'rxjs';

const sub = new Subject<number>();
sub.next(1);

sub.subscribe(x => console.log("Subscriber A:", x));

sub.next(2);
sub.next(3);

// Output:
// Subscriber A: 2
// Subscriber A: 3

Best Use Case: Button clicks, notifications, trigger events

2️⃣ BehaviorSubject

  • Stores the latest value
  • Requires an initial value
  • New subscribers immediately get the last emitted value
import { BehaviorSubject } from 'rxjs';

const bsub = new BehaviorSubject<number>(0);

bsub.subscribe(x => console.log("Subscriber A:", x));

bsub.next(10);
bsub.next(20);

bsub.subscribe(x => console.log("Subscriber B:", x));

// Output:
// Subscriber A: 0, 10, 20
// Subscriber B: 20

Best Use Case: Logged-in user data, cart count, theme mode, shared state

3️⃣ ReplaySubject

  • Stores multiple previous values and replays them to new subscribers
  • You can specify how many values to store
import { ReplaySubject } from 'rxjs';

const rsub = new ReplaySubject<number>(2);
rsub.next(1);
rsub.next(2);
rsub.next(3);

rsub.subscribe(x => console.log("Subscriber A:", x));

// Output:
// Subscriber A: 2
// Subscriber A: 3

Best Use Case: Chat messages, audit logs, history tracking

🔥 Final Comparison Table

Feature Subject BehaviorSubject ReplaySubject
Stores values ❌ No ✅ Latest ✅ Multiple
Needs initial value ❌ No ✅ Yes ❌ No
Late subscribers get old values ❌ No ✅ Last one ✅ Multiple
Use case Events (clicks, triggers) Shared state (login user, cart count) History/data replay

Real Angular Use Case: BehaviorSubject for Login State

private user$ = new BehaviorSubject<string | null>(null);

setUser(name: string) {
  this.user$.next(name);
}

getUser() {
  return this.user$.asObservable();
}

💡 One-Liner Summary

  • Subject → event stream, no memory
  • BehaviorSubject → state stream, remembers last value
  • ReplaySubject → remembers multiple previous values

What are Angular Lifecycle Hooks?

Answer:

Angular Lifecycle Hooks are special methods that allow developers to tap into different stages of a component or directive’s lifecycle—creation, rendering, change detection, and destruction. They help manage initialization, data updates, DOM access, and cleanup in a structured way.


List all Angular lifecycle hooks.

Answer:

  1. ngOnChanges – called when @Input() properties change.
  2. ngOnInit – called once after first ngOnChanges.
  3. ngDoCheck – called during every change detection cycle.
  4. ngAfterContentInit – called after projected <ng-content> content is initialized.
  5. ngAfterContentChecked – after every check of projected content.
  6. ngAfterViewInit – after component’s view and child views are initialized.
  7. ngAfterViewChecked – after every check of component view.
  8. ngOnDestroy – called just before component/directive is destroyed.

What is the difference between constructor and ngOnInit?

Answer:

  • Constructor: Runs first, only used for dependency injection. Inputs are not yet available.
  • ngOnInit: Runs after first ngOnChanges. Used to initialize data, call APIs, set up forms, etc.

What is ngOnChanges and when is it used?

Answer:

  • Triggered whenever an @Input() property changes.
  • Receives a SimpleChanges object with previousValue and currentValue.
  • Used to react to parent data changes dynamically.

@Input() userId: number;

ngOnChanges(changes: SimpleChanges) {
  if (changes['userId']) {
    this.loadUser(changes['userId'].currentValue);
  }
}

What is ngDoCheck? When should it be used?

Answer:

  • Called on every change detection cycle.
  • Used for custom change detection, like detecting mutations in arrays or objects that Angular doesn’t automatically detect.
  • ⚠️ Use sparingly; frequent execution can affect performance.

Explain ngAfterContentInit and ngAfterContentChecked.

Answer:

  • ngAfterContentInit: Called once after <ng-content> is projected into the component.
  • ngAfterContentChecked: Called every change detection for projected content.
  • Use cases: Access or validate dynamic content from parent components.

Explain ngAfterViewInit and ngAfterViewChecked.

Answer:

  • ngAfterViewInit: Called once after the component view and child views are fully initialized.
    • Use for accessing @ViewChild or @ViewChildren.
  • ngAfterViewChecked: Called after every change detection of the component view.
    • Use for post-render updates (charts, tables, or dynamic DOM manipulations).

What is ngOnDestroy and why is it important?

Answer:

  • Called just before a component is destroyed.
  • Used for cleanup tasks such as unsubscribing from observables, clearing timers, or removing event listeners.
  • Enterprise importance: Prevents memory leaks in large applications.

ngOnDestroy() {
  this.destroy$.next();
  this.destroy$.complete();
  clearInterval(this.timer);
}

Can hooks be used in directives?

Answer:

Yes. Directives also have lifecycle hooks.


@Directive({ selector: '[appHighlight]' })
export class HighlightDirective implements OnInit, OnDestroy {

  constructor(private el: ElementRef) {}

  ngOnInit() {
    this.el.nativeElement.style.backgroundColor = 'yellow';
  }

  ngOnDestroy() {
    this.el.nativeElement.style.backgroundColor = '';
  }
}

What is the order of Angular lifecycle hooks?

Answer:

  1. constructor()
  2. ngOnChanges()
  3. ngOnInit()
  4. ngDoCheck()
  5. ngAfterContentInit()
  6. ngAfterContentChecked()
  7. ngAfterViewInit()
  8. ngAfterViewChecked()
  9. ngOnDestroy()

Enterprise Tip: This order is essential when debugging complex component interactions.


Difference between ngOnChanges and ngDoCheck?

ngOnChanges ngDoCheck
Triggered only for @Input() changes Triggered on every change detection cycle
Receives SimpleChanges No parameters; must manually detect changes
Automatically detects primitive/object input changes Used for custom detection logic
Runs before ngOnInit Runs multiple times after ngOnInit

Can hooks be combined in a component?

Answer:

Yes. Enterprise apps often use multiple hooks together:

  • ngOnChanges → React to parent input changes
  • ngOnInit → Fetch initial data
  • ngAfterViewInit → Initialize table or chart
  • ngOnDestroy → Unsubscribe observables

Practical enterprise use cases of hooks

  1. ngOnInit: Load users or products table from API.
  2. ngOnChanges: Update chart when parent sends new filter.
  3. ngAfterViewInit: Access Material Table paginator or sort after view initialized.
  4. ngDoCheck: Detect array mutations in complex state objects.
  5. ngOnDestroy: Clean up Subscription and timers to avoid memory leaks.

How do you manage subscriptions with hooks?

Answer:

Use ngOnDestroy with Subject + takeUntil:


private destroy$ = new Subject<void>();

ngOnInit() {
  this.api.getData()
    .pipe(takeUntil(this.destroy$))
    .subscribe();
}

ngOnDestroy() {
  this.destroy$.next();
  this.destroy$.complete();
}

✅ Enterprise pattern to prevent memory leaks.


Why use lifecycle hooks over constructor?

Answer:

  • Constructor: Only for dependency injection; inputs not ready.
  • Hooks: Allow safe access to inputs, views, content, and subscriptions.
  • In enterprise apps, hooks ensure predictable component behavior and performance.

Can hooks be used with Observables and AsyncPipe?

Answer:

  • ngOnInit → Subscribe to API or store observable.
  • ngOnDestroy → Unsubscribe manually if not using async pipe.
  • Async pipe auto-unsubscribes, so no manual cleanup is needed.

users$ = this.api.getUsers(); // directly use in template with async pipe

⭐ Interview Tip

Always mention:

  • Cleanup in ngOnDestroy
  • Difference between constructor and ngOnInit
  • Reacting to @Input changes with ngOnChanges
  • Accessing child elements with ngAfterViewInit

Interviewers love seeing enterprise-safe practices.

Comments

Popular posts from this blog

Debouncing & Throttling in RxJS: Optimizing API Calls and User Interactions

Promises in Angular

Comprehensive Guide to C# and .NET Core OOP Concepts and Language Features