
Table of contents
Open Table of contents
The Problem
In enterprise Angular applications, you often need to show a loader while specific HTTP requests are in progress. The challenge? Not all requests need the same treatment:
- Some requests require a full-page loader blocking user interaction
- Other requests are background calls that shouldn’t block the UI
- Some might need section-specific loaders
- Managing this selectively across your entire app becomes tedious and repetitive
Traditional approaches require manually calling showLoader() and hideLoader() before and after every HTTP call, cluttering your code and breaking DRY principles.
The Solution: Decorators
Instead of sprinkling loader logic throughout your code, use a simple decorator:
@LoaderEnabled()
getSomeData(): Observable<any> {
return this.http.get('/api/data');
}
That’s it! The loader is automatically managed for that request alone—no additional code needed.
How It Works
The implementation involves three key components:
1. Loader Component & Service
Create a shared LoaderComponent that displays globally and a LoaderService that manages the loader state:
- Display a centered loader with backdrop
- Disable user interactions while loader is active
- Manage show/hide through a flag in the service
2. The Decorator
The @LoaderEnabled() decorator is the magic:
export function LoaderEnabled() {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
LoaderService.showLoader();
const result = originalMethod.apply(this, args);
if (result instanceof Observable) {
return result.pipe(
map(data => {
LoaderService.hideLoader();
return data;
}),
catchError(error => {
LoaderService.hideLoader();
throw error;
})
);
}
return result;
};
return descriptor;
};
}
What it does:
- Injects
showLoader()call before the method executes - Wraps the Observable with
mapandcatchErroroperators - Calls
hideLoader()when the HTTP request completes (success or error) - Preserves the original method functionality
3. Usage
// Show loader for this specific request
@LoaderEnabled()
getUsers(): Observable<User[]> {
return this.http.get<User[]>('/api/users');
}
// No loader for background requests
getBackgroundData(): Observable<any> {
return this.http.get('/api/background');
}
// Even use on interceptor for all requests
@LoaderEnabled()
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req);
}
Key Benefits
- Clean & DRY - One decorator line instead of repeating loader logic everywhere
- Selective - Control exactly which requests show loaders
- Maintainable - Changes to loader behavior happen in one place
- Type-Safe - Works seamlessly with TypeScript and Angular services
- Flexible - Use on any method returning an Observable
Advanced Improvements
The article also covers several enhancements:
- Delayed Loader - Only show loader after 200ms to avoid flickering on quick requests
- Request Counter - Track concurrent requests to avoid hiding loader prematurely
- Selective Interception - Combine with HttpInterceptor for smarter loader management
Read the Full Article
Originally published for Medium - Written during my early Angular journey.
For complete implementation details, working demos, and StackBlitz code:
📖 Decorator-Based Loader for Angular HttpClient
The article includes full code examples, architecture diagrams, and a live working demo you can explore and customize.
Key Takeaways
Decorators are powerful tools for reducing boilerplate code in Angular. This decorator-based approach solves a common problem elegantly without:
- Modifying standard Angular HttpClient
- Cluttering your service methods
- Breaking inheritance or extending classes
- Sacrificing flexibility or control
If you’re building enterprise Angular applications, this pattern is worth adopting for any cross-cutting concerns like loaders, logging, or request tracking.