Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

441
Vistas
Angular show spinner para cada solicitud HTTP con muy pocos cambios de código

Estoy trabajando en una aplicación Angular existente. La versión es Angular 4.

La aplicación realiza llamadas HTTP a una API REST desde varios componentes.

Quiero mostrar un control giratorio personalizado para cada solicitud HTTP. Dado que esta es una aplicación existente, hay muchos lugares donde se realizan llamadas a la API REST. Y cambiar el código uno en todos los lugares no es una opción factible.

Me gustaría implementar una solución abstracta que resolvería este problema.

Por favor sugiera si hay alguna opción.

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

@jornare tiene una buena idea en su solución. Está manejando el caso para múltiples solicitudes. Sin embargo, el código podría escribirse de manera más simple, sin crear nuevas solicitudes observables y de almacenamiento en la memoria. El siguiente código también usa RxJS 6 con operadores canalizables:

 import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, HttpInterceptor, HttpResponse } from '@angular/common/http'; import { finalize } from 'rxjs/operators'; import { LoadingService } from '@app/services/loading.service'; import { of } from 'rxjs'; @Injectable() export class LoadingInterceptor implements HttpInterceptor { private totalRequests = 0; constructor(private loadingService: LoadingService) { } intercept(request: HttpRequest<any>, next: HttpHandler) { this.totalRequests++; this.loadingService.setLoading(true); return next.handle(request).pipe( finalize(res => { this.totalRequests--; if (this.totalRequests === 0) { this.loadingService.setLoading(false); } }) ); } }

Agregue este servicio de interceptor a sus proveedores de módulos:

 @NgModule({ // ... providers: [ { provide: HTTP_INTERCEPTORS, useClass: LoadingInterceptor, multi: true } ] }) export class AppModule { }

Aquí hay un ejemplo de la implementación de LoadingService :

 @Injectable() export class LoadingService { private isLoading$$ = new BehaviorSubject<boolean>(false); isLoading$ = this.isLoading$$.asObservable(); setLoading(isLoading: boolean) { this.isLoading$$.next(isLoading); } }

Y así es como usaría LoadingService en un componente:

 @Component({ selector: 'app-root', template: ` <ng-container *ngIf="loadingService.isLoading$ | async"> <i class="loading"></i> </ng-container> <router-outlet></router-outlet> `, changeDetection: ChangeDetectionStrategy.OnPush }) export class AppComponent { constructor(public loadingService: LoadingService) {} }
over 4 years ago · Santiago Trujillo Denunciar

0

Angular 4+ tiene un nuevo HttpClient que admite HttpInterceptors. Esto le permite insertar código que se ejecutará cada vez que realice una solicitud HTTP.

Es importante notar que HttpRequest no son Observables de larga duración, pero terminan después de la respuesta. Además, si se cancela la suscripción del observable antes de que se haya devuelto la respuesta, la solicitud se cancela y no se procesa ninguno de los controladores. Por lo tanto, puede terminar con una barra de carga "colgada", que nunca desaparece. Esto suele suceder si navega un poco rápido en su aplicación.

Para solucionar este último problema, necesitamos crear un nuevo Observable para poder adjuntar la lógica de desmontaje.

Devolvemos esto en lugar del Observable original. También debemos realizar un seguimiento de todas las solicitudes realizadas, ya que podemos ejecutar más de una solicitud a la vez.

También necesitamos un servicio que pueda contener y compartir el estado de si tenemos solicitudes pendientes.

 @Injectable() export class MyLoaderService { // A BehaviourSubject is an Observable with a default value public isLoading = new BehaviorSubject<boolean>(false); constructor() {} }

El Interceptor utiliza el MyLoaderService

 @Injectable() export class MyLoaderInterceptor implements HttpInterceptor { private requests: HttpRequest<any>[] = []; constructor(private loaderService: MyLoaderService) { } removeRequest(req: HttpRequest<any>) { const i = this.requests.indexOf(req); this.requests.splice(i, 1); this.loaderService.isLoading.next(this.requests.length > 0); } intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { this.requests.push(req); this.loaderService.isLoading.next(true); return Observable.create(observer => { const subscription = next.handle(req) .subscribe( event => { if (event instanceof HttpResponse) { this.removeRequest(req); observer.next(event); } }, err => { this.removeRequest(req); observer.error(err); }, () => { this.removeRequest(req); observer.complete(); }); // teardown logic in case of cancelled requests return () => { this.removeRequest(req); subscription.unsubscribe(); }; }); } }

Finalmente, en nuestro Componente, podemos usar el mismo MyLoaderService y con el operador asíncrono ni siquiera necesitamos suscribirnos. Dado que el valor de origen que queremos usar es de un servicio, debe compartirse como un Observable para que obtenga un alcance/zona de representación donde se usa. Si es solo un valor, es posible que no actualice su GUI como desea.

 @Component({...}) export class MyComponent { constructor(public myLoaderService: MyLoaderService) {} }

Y una plantilla de ejemplo usando async

 <div class="myLoadBar" *ngIf="myLoaderService.isLoading | async">Loading!</div>

Supongo que sabe cómo proporcionar servicios y configurar módulos correctamente. También puede ver un ejemplo de trabajo en Stackblitz

over 4 years ago · Santiago Trujillo Denunciar

0

En Angular 5 viene el módulo HttpClient . Puede encontrar más información allí .

Con este módulo, viene algo llamado interceptors .

Le permiten hacer algo para cada solicitud HTTP.

Si migra de Http a HttpClient (y debería, Http quedará obsoleto), puede crear un interceptor que pueda manejar una variable en un servicio compartido:

 intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { this.sharedService.loading = true; return next .handle(req) .finally(() => this.sharedService.loading = false); }

Ahora solo tiene que usar esta variable en sus plantillas.

 <spinner *ngIf="sharedService.loading"></spinner>

(Asegúrese de tener una inyección de su servicio en los componentes que muestran esta rueda giratoria)

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda