英文:
Set only single loader while hitting multiple http requests continuously using ngx-ui-loader in angular
问题
我已经实现了ngx-ui-loader并为每个HTTP请求启用了NgxUiLoaderHttpModule,它运行良好。但问题在于我的项目的某些路由上,会连续执行多个HTTP请求,并且加载器会在每个请求之后启动并在响应后停止,然后再为下一个请求重新启动,这看起来很不美观。所以是否有办法只显示一个加载器,用于所有连续的HTTP请求?
提前感谢!
我尝试了各种方法,但都没有成功。
英文:
I have implemented this ngx-ui-loader and set the NgxUiLoaderHttpModule for every HTTP request hits and it is working fine. But the issue is on some routes of my project, there are continuously multiple HTTP requests executed, and the loader start for every requests and stops after the response and then again starts for next request which looks awful. So is there any way to show only single loader for all continuous HTTP requests?
Thanks in advance!
I have tried various method but it didn't work.
答案1
得分: 2
以下是翻译好的部分:
@sfelli提出的解决方案很简单,但如果多个请求同时结束,可能会遇到问题。
`this.ngxService.stop()` 可能会被多次调用或者从未被调用 :-(
我找到的解决此问题的方法是使用RxJs的NEVER可观察对象。
下面是拦截器的重构代码:
import { Injectable } from '@angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { NgxUiLoaderService } from 'ngx-ui-loader';
import { catchError, finalize } from 'rxjs/operators';
@Injectable()
export class NgxHttpInterceptor implements HttpInterceptor {
constructor(private readonly ngxService: NgxUiLoaderService) { }
private readonly spinner$ = defer(() => {
this.ngxService.start();
return NEVER.pipe(
finalize(() => {
this.ngxService.stop();
})
);
}).pipe(share());
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const spinnerSubscription: Subscription = this.spinner$.subscribe();
return next.handle(req).pipe(finalize(() => spinnerSubscription.unsubscribe()));
}
}
我做了一篇更深入描述这个解决方案的文章:在处理HTTP请求并发时显示加载器
英文:
The solution proposed by @sfelli is easy but you may face issue if multiple requests end in the same time.
this.ngxService.stop()
may be called mutiple times or never called
The solution I found to overcome this issue is to use RxJs NEVER observable.
Hereafter is a refactoring of the interceptor :
import { Injectable } from '@angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { NgxUiLoaderService } from 'ngx-ui-loader';
import { catchError, finalize } from 'rxjs/operators';
@Injectable()
export class NgxHttpInterceptor implements HttpInterceptor {
constructor(private readonly ngxService: NgxUiLoaderService) { }
private readonly spinner$ = defer(() => {
this.ngxService.start();
return NEVER.pipe(
finalize(() => {
this.ngxService.stop();
})
);
}).pipe(share());
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const spinnerSubscription: Subscription = this.spinner$.subscribe();
return next.handle(req).pipe(finalize(() => spinnerSubscription.unsubscribe()));
}
}
I made an article decribing more deeply this solution : Show loader during HTTP request handeling concurrency
答案2
得分: 1
简单的实现方式:
步骤 1 - 创建自定义 HttpInterceptor 类:
import { Injectable } from '@angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { NgxUiLoaderService } from 'ngx-ui-loader';
import { catchError, finalize } from 'rxjs/operators';
@Injectable()
export class NgxHttpInterceptor implements HttpInterceptor {
private count = 0;
constructor(private ngxService: NgxUiLoaderService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.ngxService.start();
this.count++;
return next.handle(req).pipe(
catchError(error => {
return of(error);
}),
finalize(() => {
this.count--;
if (this.count === 0) {
this.ngxService.stop();
}
})
);
}
}
步骤 2 在你的 AppModule 中注册 CustomHttpInterceptor 类:
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { CustomHttpInterceptor } from './custom-http-interceptor';
@NgModule({
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: CustomHttpInterceptor, multi: true }
]
})
export class AppModule { }
在所有连续的 HTTP 请求期间,将只显示一个加载器。加载器将在第一个请求之前启动,并在最后一个响应之后停止。
英文:
The easy way to do it:
Step 1- Create a custom HttpInterceptor class:
import { Injectable } from '@angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { NgxUiLoaderService } from 'ngx-ui-loader';
import { catchError, finalize } from 'rxjs/operators';
@Injectable()
export class NgxHttpInterceptor implements HttpInterceptor {
private count = 0;
constructor(private ngxService: NgxUiLoaderService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.ngxService.start();
this.count++;
return next.handle(req).pipe(
catchError(error => {
return of(error);
}),
finalize(() => {
this.count--;
if (this.count === 0) {
this.ngxService.stop();
}
})
);
}
}
Step 2 Register the CustomHttpInterceptor class in your AppModule:
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { CustomHttpInterceptor } from './custom-http-interceptor';
@NgModule({
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: CustomHttpInterceptor, multi: true }
]
})
export class AppModule { }
You will have only a single loader displayed during all continuous HTTP requests. The loader will start once before the first request and stop after the last response.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论