Hone logo
Hone
Problems

Angular Loading Interceptor Challenge

Your task is to implement a loading interceptor in Angular. This interceptor will globally manage a loading indicator, showing it whenever an HTTP request is sent and hiding it when all requests are completed. This is a common and crucial feature for improving user experience in web applications, providing visual feedback during data fetching.

Problem Description

You need to create an Angular HTTP interceptor that toggles a loading state. This state should be managed by a service and exposed to the application.

Key Requirements:

  1. Create a LoadingService:

    • This service should maintain a boolean property (e.g., isLoading) to indicate if any HTTP requests are currently in progress.
    • It should provide methods to increment and decrement a counter for active requests.
    • The isLoading property should be true if the counter is greater than 0, and false otherwise.
    • Consider making isLoading an Observable so components can subscribe to changes.
  2. Create an LoadingInterceptor:

    • This interceptor must implement the HttpInterceptor interface from @angular/common/http.
    • In the intercept method:
      • When a request is initiated, increment the active request counter in the LoadingService.
      • Regardless of success or failure, when a request completes (either success or error), decrement the active request counter in the LoadingService.
      • The interceptor should return the request itself, possibly modified, or a next.handle(request) result.
  3. Register the Interceptor:

    • Ensure the LoadingInterceptor is correctly registered in your Angular module's providers, typically in app.module.ts. It should be provided with HTTP_INTERCEPTORS and set to multi-use.
  4. Component Integration (Conceptual):

    • Although you won't be building the full UI, understand how a component would use the LoadingService. A component would inject LoadingService and subscribe to its isLoading observable to conditionally display a loading spinner or message.

Expected Behavior:

  • When an HTTP request is made by any Angular service, the loading indicator should become visible.
  • When all active HTTP requests have finished (either successfully or with an error), the loading indicator should become hidden.
  • If multiple requests are made concurrently, the loading indicator should remain visible until the last request completes.

Edge Cases to Consider:

  • Multiple Concurrent Requests: The interceptor must correctly handle scenarios where many requests are active simultaneously.
  • Request Failures: The loading indicator must be hidden even if a request results in an error.
  • Interceptors in Sequence: If other interceptors are present, ensure your loading interceptor is placed correctly in the chain to accurately track requests.

Examples

This is a conceptual example as the "input" and "output" are more about observable state changes and component behavior rather than concrete data transformations.

Example 1: Single Request

Imagine a component calls a service that makes a single GET request to fetch user data.

  • Before Request: LoadingService.isLoading is false.
  • Request Initiated: LoadingInterceptor intercepts the request. It calls LoadingService.incrementRequestCount(). LoadingService.isLoading becomes true. A loading spinner is displayed in the UI.
  • Request Completes (Success): LoadingInterceptor intercepts the response. It calls LoadingService.decrementRequestCount(). LoadingService.isLoading becomes false (as the count is now 0). The loading spinner is hidden.
  • Request Completes (Error): LoadingInterceptor intercepts the error. It calls LoadingService.decrementRequestCount(). LoadingService.isLoading becomes false (as the count is now 0). The loading spinner is hidden.

Example 2: Multiple Concurrent Requests

Imagine a dashboard component that makes three GET requests simultaneously to fetch different data sets.

  • Before Requests: LoadingService.isLoading is false.
  • Request 1 Initiated: LoadingInterceptor increments count. LoadingService.isLoading is true.
  • Request 2 Initiated: LoadingInterceptor increments count. LoadingService.isLoading is true. (Count is now 2).
  • Request 3 Initiated: LoadingInterceptor increments count. LoadingService.isLoading is true. (Count is now 3).
  • Request 1 Completes (Success): LoadingInterceptor decrements count. (Count is now 2). LoadingService.isLoading remains true.
  • Request 2 Completes (Error): LoadingInterceptor decrements count. (Count is now 1). LoadingService.isLoading remains true.
  • Request 3 Completes (Success): LoadingInterceptor decrements count. (Count is now 0). LoadingService.isLoading becomes false. Loading spinner is hidden.

Constraints

  • The LoadingService must be provided as a singleton.
  • The LoadingInterceptor must be registered as an HTTP interceptor for all outgoing requests.
  • The solution must be written in TypeScript.
  • The interceptor should not block the request flow; it should simply observe and act.

Notes

  • Think about using RxJS operators like tap for side effects within the interceptor's observable stream.
  • Consider using Subject or BehaviorSubject in your LoadingService to manage the isLoading state and allow for subscriptions.
  • The next.handle(request) call is crucial within the intercept method to ensure the request continues down the interceptor chain.
  • You will need to inject LoadingService into your LoadingInterceptor.
Loading editor...
typescript