Angular Interview Questions

51 Angular Questions to Pass Any Interview: A Comprehensive Guide

Table of Contents

  1. Component Architecture & Communication

  2. Lazy Loading & Module System

  3. Dependency Injection & Services

  4. Change Detection & Performance

  5. RxJS & Observables

  6. Advanced Angular Concepts


Component Architecture & Communication

1. What are the various ways of Component communications?

Angular provides several methods for component communication[70][73]:

Parent to Child Communication:

// Parent Component
@Component({
  template: `<app-child [data]="parentData"></app-child>`
})
export class ParentComponent {
  parentData = 'Hello from Parent';
}

// Child Component
@Component({
  selector: 'app-child'
})
export class ChildComponent {
  @Input() data: string;
}

Child to Parent Communication:

// Child Component
@Component({
  selector: 'app-child'
})
export class ChildComponent {
  @Output() messageEvent = new EventEmitter<string>();

  sendMessage() {
    this.messageEvent.emit('Hello from Child');
  }
}

// Parent Component
@Component({
  template: `<app-child (messageEvent)="receiveMessage($event)"></app-child>`
})
export class ParentComponent {
  receiveMessage(message: string) {
    console.log(message);
  }
}

Service-based Communication:

@Injectable({ providedIn: 'root' })
export class DataService {
  private messageSource = new BehaviorSubject<string>('Initial Message');
  currentMessage = this.messageSource.asObservable();

  changeMessage(message: string) {
    this.messageSource.next(message);
  }
}

2. What do you understand by life cycle hooks of a Component?

Angular components have a well-defined lifecycle managed by Angular[37][40]:

@Component({
  selector: 'app-lifecycle'
})
export class LifecycleComponent implements OnInit, OnChanges, OnDestroy {
  @Input() inputValue: string;

  // Called after data-bound input properties change
  ngOnChanges(changes: SimpleChanges): void {
    console.log('Input changed:', changes);
  }

  // Called once after component initialization
  ngOnInit(): void {
    console.log('Component initialized');
  }

  // Called during every change detection run
  ngDoCheck(): void {
    console.log('Change detection run');
  }

  // Called once before component destruction
  ngOnDestroy(): void {
    console.log('Component destroyed');
  }
}

3. Which one will be called first, ngOnChange or ngOnInit? Explain with a scenario.

ngOnChanges is called first[37][46]. Here's the execution order:

@Component({
  selector: 'app-example'
})
export class ExampleComponent implements OnInit, OnChanges {
  @Input() userData: any;

  ngOnChanges(changes: SimpleChanges): void {
    console.log('1. ngOnChanges called first');
    // Called whenever @Input properties change
  }

  ngOnInit(): void {
    console.log('2. ngOnInit called second');
    // Called once after first ngOnChanges
  }
}

Scenario: When a parent passes data to a child component, Angular first detects the input change (triggering ngOnChanges), then initializes the component (triggering ngOnInit).

7. What do you understand by ViewChild and ContentChild?

ViewChild accesses elements within the component's template, while ContentChild accesses projected content[38][41]:

// ViewChild Example
@Component({
  selector: 'app-parent',
  template: `
    <app-child #childRef></app-child>
    <input #inputRef>
  `
})
export class ParentComponent implements AfterViewInit {
  @ViewChild('childRef') childComponent: ChildComponent;
  @ViewChild('inputRef') inputElement: ElementRef;

  ngAfterViewInit() {
    console.log(this.childComponent); // Access child component
    console.log(this.inputElement.nativeElement); // Access DOM element
  }
}

// ContentChild Example
@Component({
  selector: 'app-container',
  template: `
    <div>
      <h3>Container</h3>
      <ng-content></ng-content>
    </div>
  `
})
export class ContainerComponent implements AfterContentInit {
  @ContentChild(ChildComponent) projectedChild: ChildComponent;

  ngAfterContentInit() {
    console.log(this.projectedChild); // Access projected content
  }
}

// Usage
@Component({
  template: `
    <app-container>
      <app-child></app-child>
    </app-container>
  `
})
export class AppComponent {}

34. Can you explain difference between ContentChild and ViewChild

Key Differences:

ViewChildContentChild
Accesses elements in component's templateAccesses projected content via <ng-content>
Available in ngAfterViewInit()Available in ngAfterContentInit()
Direct template childrenContent projection children

Lazy Loading & Module System

14. What do you understand by lazy loaded modules?

Lazy loading defers module loading until needed, improving initial app performance[24][27][30]:

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

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {}

// Feature Module
@NgModule({
  declarations: [FeatureComponent],
  imports: [
    CommonModule,
    RouterModule.forChild([
      { path: '', component: FeatureComponent }
    ])
  ]
})
export class FeatureModule {}

15. For a service how many objects Angular creates for lazy loaded modules?

Angular creates one instance per injector hierarchy[25][28]. For lazy-loaded modules:

// Service provided at root level - ONE instance across entire app
@Injectable({ providedIn: 'root' })
export class GlobalService {}

// Service provided at module level - ONE instance per module
@NgModule({
  providers: [ModuleLevelService]
})
export class LazyModule {}

// Service provided at component level - ONE instance per component
@Component({
  providers: [ComponentLevelService]
})
export class MyComponent {}

17. How to dynamically load a component? can you explain me the process?

Dynamic component loading allows runtime component creation[101][104][107]:

// Dynamic Component Directive
@Directive({
  selector: '[dynamicHost]'
})
export class DynamicDirective {
  constructor(public viewContainerRef: ViewContainerRef) {}
}

// Container Component
@Component({
  selector: 'app-dynamic-container',
  template: `
    <div class="dynamic-container">
      <ng-template dynamicHost></ng-template>
    </div>
    <button (click)="loadComponent()">Load Dynamic Component</button>
  `
})
export class DynamicContainerComponent implements OnInit {
  @ViewChild(DynamicDirective, { static: true }) 
  dynamicHost: DynamicDirective;

  loadComponent() {
    const viewContainerRef = this.dynamicHost.viewContainerRef;
    viewContainerRef.clear();

    // Create component dynamically
    const componentRef = viewContainerRef.createComponent(DynamicContentComponent);

    // Pass data to dynamic component
    componentRef.instance.data = 'Dynamic data';
  }
}

// Dynamic Content Component
@Component({
  selector: 'app-dynamic-content',
  template: `<h2>{{ data }}</h2>`
})
export class DynamicContentComponent {
  @Input() data: string;
}

Dependency Injection & Services

9. What do you understand by Angular Service?

Angular services provide shared functionality across components using dependency injection[39][42]:

@Injectable({ providedIn: 'root' })
export class DataService {
  private apiUrl = 'https://api.example.com';

  constructor(private http: HttpClient) {}

  getData(): Observable<any> {
    return this.http.get(`${this.apiUrl}/data`);
  }

  saveData(data: any): Observable<any> {
    return this.http.post(`${this.apiUrl}/data`, data);
  }
}

// Using service in component
@Component({
  selector: 'app-data'
})
export class DataComponent implements OnInit {
  data: any;

  constructor(private dataService: DataService) {}

  ngOnInit() {
    this.dataService.getData().subscribe(
      data => this.data = data
    );
  }
}

11. What is difference between provideIn and providers?

providedIn vs providers configuration[39][45]:

// providedIn: 'root' - Service available application-wide
@Injectable({ providedIn: 'root' })
export class GlobalService {}

// Module-level providers
@NgModule({
  providers: [
    { provide: LocalService, useClass: LocalService }
  ]
})
export class FeatureModule {}

// Component-level providers
@Component({
  providers: [
    { provide: ComponentService, useClass: ComponentService }
  ]
})
export class MyComponent {}

// Different provider configurations
@NgModule({
  providers: [
    // Class provider
    { provide: MyService, useClass: MyService },

    // Value provider  
    { provide: API_URL, useValue: 'https://api.example.com' },

    // Factory provider
    { 
      provide: ConfigService, 
      useFactory: (http: HttpClient) => new ConfigService(http),
      deps: [HttpClient]
    },

    // Existing provider
    { provide: Logger, useExisting: ConsoleLogger }
  ]
})
export class AppModule {}

Change Detection & Performance

20. What do you understand by Change Detection?

Angular's change detection mechanism keeps the view synchronized with the component state[26][29][32]:

@Component({
  selector: 'app-change-detection',
  template: `
    <h2>{{ title }}</h2>
    <p>Count: {{ count }}</p>
    <button (click)="increment()">Increment</button>
  `
})
export class ChangeDetectionComponent {
  title = 'Change Detection Demo';
  count = 0;

  increment() {
    this.count++; // Triggers change detection
  }
}

Change Detection Triggers:

  • DOM events (click, keyup, etc.)

  • HTTP requests

  • Timers (setTimeout, setInterval)

  • Promises and Observables

22. What is difference between detectChange and markForCheck

detectChange vs markForCheck for manual change detection control[29][72]:

@Component({
  selector: 'app-manual-detection',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ManualDetectionComponent {

  constructor(private cdr: ChangeDetectorRef) {}

  // markForCheck - marks component and ancestors for checking
  updateWithMarkForCheck() {
    this.data = newData;
    this.cdr.markForCheck(); // Schedules check in next detection cycle
  }

  // detectChanges - immediately runs change detection
  updateWithDetectChanges() {
    this.data = newData;
    this.cdr.detectChanges(); // Runs change detection immediately
  }
}

23. What do you understand by dumb component and smart component?

Smart vs Dumb Component Pattern[69][72]:

// Smart Component (Container)
@Component({
  selector: 'app-user-container',
  template: `
    <app-user-list 
      [users]="users$ | async"
      (userSelected)="onUserSelected($event)">
    </app-user-list>
  `
})
export class UserContainerComponent {
  users$ = this.userService.getUsers();

  constructor(private userService: UserService) {}

  onUserSelected(user: User) {
    this.userService.selectUser(user);
  }
}

// Dumb Component (Presentation)
@Component({
  selector: 'app-user-list',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <div *ngFor="let user of users" (click)="selectUser(user)">
      {{ user.name }}
    </div>
  `
})
export class UserListComponent {
  @Input() users: User[];
  @Output() userSelected = new EventEmitter<User>();

  selectUser(user: User) {
    this.userSelected.emit(user);
  }
}

RxJS & Observables

24. What is difference between promise and observables

Promise vs Observable comparison[68][71]:

// Promise - Single value, eager execution
const promise = new Promise((resolve) => {
  console.log('Promise executed immediately');
  setTimeout(() => resolve('Promise result'), 1000);
});

promise.then(result => console.log(result));

// Observable - Multiple values, lazy execution
const observable = new Observable(observer => {
  console.log('Observable executed only when subscribed');
  let count = 0;
  const interval = setInterval(() => {
    observer.next(`Observable result ${count++}`);
  }, 1000);

  return () => clearInterval(interval); // Cleanup function
});

const subscription = observable.subscribe(result => console.log(result));

// Unsubscribe after 5 seconds
setTimeout(() => subscription.unsubscribe(), 5000);

25. What is difference between observable and subjects?

Observable vs Subject differences[68][71][77]:

// Observable - Unicast (one-to-one)
const observable = new Observable(observer => {
  observer.next(Math.random());
});

// Each subscription gets different values
observable.subscribe(value => console.log('Sub1:', value));
observable.subscribe(value => console.log('Sub2:', value));

// Subject - Multicast (one-to-many)
const subject = new Subject<number>();

// Both subscriptions get same values
subject.subscribe(value => console.log('Sub1:', value));
subject.subscribe(value => console.log('Sub2:', value));

subject.next(Math.random()); // Both subscribers get same value

// BehaviorSubject - Holds current value
const behaviorSubject = new BehaviorSubject<string>('Initial Value');

behaviorSubject.subscribe(value => console.log('Early Sub:', value));
behaviorSubject.next('Updated Value');
behaviorSubject.subscribe(value => console.log('Late Sub:', value)); // Gets current value

27. When we should use BehaviorSubject?

BehaviorSubject Use Cases[68][74][77]:

// State Management Service
@Injectable({ providedIn: 'root' })
export class StateService {
  private userState = new BehaviorSubject<User | null>(null);
  public user$ = this.userState.asObservable();

  // Always provides current user state to new subscribers
  setUser(user: User) {
    this.userState.next(user);
  }

  getCurrentUser(): User | null {
    return this.userState.getValue(); // Synchronous access
  }
}

// Component using BehaviorSubject
@Component({
  selector: 'app-user-profile'
})
export class UserProfileComponent implements OnInit {
  user$ = this.stateService.user$;

  constructor(private stateService: StateService) {}

  ngOnInit() {
    // Immediately gets current user state, even if set before subscription
    this.user$.subscribe(user => {
      console.log('Current user:', user);
    });
  }
}

30. What is async pipe?

Async Pipe automatically subscribes/unsubscribes to observables in templates[99][102][105]:

@Component({
  selector: 'app-async-demo',
  template: `
    <!-- Async pipe with Observable -->
    <div *ngFor="let item of items$ | async">{{ item.name }}</div>

    <!-- Async pipe with ngIf -->
    <div *ngIf="user$ | async as user">
      Hello, {{ user.name }}!
    </div>

    <!-- Loading state -->
    <div *ngIf="!(data$ | async); else dataTemplate">
      Loading...
    </div>
    <ng-template #dataTemplate let-data>
      <div>{{ data | json }}</div>
    </ng-template>
  `
})
export class AsyncDemoComponent {
  items$ = this.dataService.getItems();
  user$ = this.userService.getCurrentUser();
  data$ = this.apiService.getData();

  constructor(
    private dataService: DataService,
    private userService: UserService,
    private apiService: ApiService
  ) {}
}

Advanced Angular Concepts

19. What is purpose of @HostBinding

@HostBinding binds properties to the host element[search results indicate this is a directive feature]:

@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective {
  @HostBinding('class.highlighted') 
  get cssClass() {
    return this.isHighlighted;
  }

  @HostBinding('style.backgroundColor') 
  backgroundColor = 'yellow';

  @HostBinding('attr.role') 
  role = 'button';

  private isHighlighted = false;

  @HostListener('mouseenter')
  onMouseEnter() {
    this.isHighlighted = true;
    this.backgroundColor = 'lightblue';
  }

  @HostListener('mouseleave')  
  onMouseLeave() {
    this.isHighlighted = false;
    this.backgroundColor = 'yellow';
  }
}

21. When we should use onPush?

OnPush Change Detection Strategy should be used for performance optimization[69][72][75]:

@Component({
  selector: 'app-optimized',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <h2>{{ title }}</h2>
    <div>{{ data | json }}</div>
  `
})
export class OptimizedComponent {
  @Input() data: any; // Must be immutable for OnPush to work
  title = 'Optimized Component';

  constructor(private cdr: ChangeDetectorRef) {}

  // Use OnPush when:
  // 1. Component receives data via @Input only
  // 2. Data is immutable
  // 3. Component doesn't perform internal state changes
  // 4. Performance is critical
}

// Parent component must pass immutable data
@Component({
  template: `<app-optimized [data]="immutableData"></app-optimized>`
})
export class ParentComponent {
  immutableData = { name: 'John', age: 30 };

  updateData() {
    // Create new object reference for OnPush detection
    this.immutableData = { ...this.immutableData, age: 31 };
  }
}

29. Is it ok to use observable if not why?

Avoid Observable for type safety[search results suggest this is not recommended]:

// ❌ Bad - No type safety
getData(): Observable<any> {
  return this.http.get('/api/data');
}

// ✅ Good - Proper typing
interface User {
  id: number;
  name: string;
  email: string;
}

getUser(): Observable<User> {
  return this.http.get<User>('/api/user');
}

// ✅ Better - Generic types
getItems<T>(): Observable<T[]> {
  return this.http.get<T[]>('/api/items');
}

// Usage with type safety
this.userService.getUser().subscribe(user => {
  console.log(user.name); // TypeScript knows 'name' exists
  // console.log(user.invalid); // TypeScript error
});

31. What do you understand by union type and intersection type?

TypeScript Types in Angular[search results indicate this is TypeScript knowledge]:

// Union Type - Can be one of several types
type Status = 'loading' | 'success' | 'error';
type StringOrNumber = string | number;

@Component({
  selector: 'app-status'
})
export class StatusComponent {
  status: Status = 'loading';
  value: StringOrNumber = 'hello';

  updateStatus(newStatus: Status) {
    this.status = newStatus; // Only accepts 'loading', 'success', or 'error'
  }
}

// Intersection Type - Combines multiple types
interface User {
  name: string;
  email: string;
}

interface Admin {
  permissions: string[];
  level: number;
}

type AdminUser = User & Admin; // Has properties from both interfaces

@Injectable()
export class UserService {
  createAdminUser(): AdminUser {
    return {
      name: 'John Doe',
      email: 'john@example.com',
      permissions: ['read', 'write'],
      level: 5
    };
  }
}

33. What is purpose of component resolver

Component Resolver (Angular Resolver) pre-fetches data before route activation:

// User Resolver
@Injectable()
export class UserResolver implements Resolve<User> {
  constructor(private userService: UserService) {}

  resolve(route: ActivatedRouteSnapshot): Observable<User> {
    const userId = route.paramMap.get('id');
    return this.userService.getUser(userId);
  }
}

// Route Configuration
const routes: Routes = [
  {
    path: 'user/:id',
    component: UserComponent,
    resolve: { user: UserResolver }
  }
];

// Component using resolved data
@Component({
  selector: 'app-user',
  template: `<h1>{{ user.name }}</h1>`
})
export class UserComponent implements OnInit {
  user: User;

  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    this.user = this.route.snapshot.data['user']; // Pre-resolved data
  }
}

Conclusion

This comprehensive guide covers the essential Angular concepts needed for technical interviews. Each topic includes practical code examples and real-world scenarios to demonstrate understanding. Focus on:

  1. Understanding core concepts - Components, services, modules

  2. Mastering component communication - @Input/@Output, services, observables

  3. Performance optimization - Lazy loading, OnPush, change detection

  4. RxJS proficiency - Observables, subjects, async pipe

  5. Advanced patterns - Dynamic components, dependency injection, resolvers

Remember to practice implementing these concepts in real projects to solidify your understanding and be prepared to discuss trade-offs and best practices during interviews.

0
Subscribe to my newsletter

Read articles from Naveen Chikkamath directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Naveen Chikkamath
Naveen Chikkamath