Synchronize changes of service variable that changes in time angular 10

883 Views Asked by At

I am trying to consume the following service in Angular 10, that is a service that looks for http requests in progress, this service changes from true to false if there are http requests, this does it fine, I check it with the console log

export class SpinnerService implements HttpInterceptor {

  public loading: boolean = false;
  
  constructor() {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    this.loading = true;
    // console.log('estado spinner: >> ', this.loading);
    return next.handle(req).pipe(
      finalize(() => {
        this.loading = false; 
        // console.log('todas solicitudes ok');
        console.log('estado espinner: >>', this.loading);
      })
    );
  }
}

When I am trying to consume the service in another component I have problems because the service is not synchronized with the local variable of the component. For example, the loading variable of the service starts false, then it becomes true then it becomes false all this in a period of time of 5 seconds that takes the rest of the API to bring the data.

The load variable is initially synchronized with the loading variable as false, but then it does not follow the states of the loading variable, the load variable remains false

How do I synchronize these variables? help please, I don't know how to search

This is the constructor where I call the service from the loading variable,

public carga = this._spinnerService.loading;
    
constructor(private _spinnerService: SpinnerService) 
{
  this.crearFormulario();  // inicializar formulario
  // this._spinnerService.loading = this.spinneres;
  // console.log('estado inicial spinner: >>', this._spinnerService.loading);
  console.log('estado inicial spinner: >>', this.carga);
} 
2

There are 2 best solutions below

0
On BEST ANSWER

I was able to solve the problem, I created the classes in the same ts file so that it was more ordered, one class is in charge of intercepting the logic and another class is in charge of listening to http requests, I checked many solutions but this was the one that most I liked it because it returns true or false to the html without the need to use dependencies.

this is the ts file of the service you use, you just have to import the service in the component you want to use spinners.

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpResponse, HttpErrorResponse } from '@angular/common/http';//para interceptor de http
import { BehaviorSubject, Observable } from 'rxjs';//para interceptor de http
import { tap } from 'rxjs/operators';//para interceptor de http


@Injectable({
  providedIn: 'root'
})

//servicio interceptor que escucha si hay solicitudes http en progreso
export class interceptHttpService implements HttpInterceptor{

  constructor(private _pruebaspinerss3 : spinnerService ) { }
  
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> 
  {    
    this._pruebaspinerss3.requestStarted();    
    return this.handler(next,request);
  }

  handler(next ,request)
  {
    return next.handle(request)
      .pipe(
          tap(
            (event) =>{
              if (event instanceof HttpResponse){
                this._pruebaspinerss3.requestEnded();  
              }
            },
            (error: HttpErrorResponse) =>{
              this._pruebaspinerss3.resetSpinner();
              throw error;
            }
          ),
      )
  };
}

export class spinnerService{
  
  private count = 0;
  private spinner$ = new BehaviorSubject<string>('');
  
  getSpinnerObserver(): Observable<string>{
    return this.spinner$.asObservable();
  }  

  requestStarted() {
    console.log('spinner activado');   
    if (++this.count === 1) {
      this.spinner$.next('start');
    }
  }

  requestEnded() {
    console.log('spinner desactivado');   
    if (this.count === 0 || --this.count === 0) {
      this.spinner$.next('stop');
    }
  }

  resetSpinner() {
    console.log('error en solicitud, reset spinner');
    this.count = 0;
    this.spinner$.next('stop');
  }
}

in file app.module ts

import { interceptHttpService, spinnerService } from './services/spinner.service';
1
On

I think what you are trying to show is a spinner on every http network call made from your application. If that is the case you are almost correct except the public variable 'loading' that you mentioned on the SpinnerService class.

import { NgxSpinnerService } from 'ngx-spinner';
export class SpinnerService implements HttpInterceptor{
            
    constructor(private spinner: NgxSpinnerService) { }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> 
    {
        this.spinner.show();
        return next.handle(req).pipe(
            finalize(() => {
                        this.spinner.hide();
                    }
            )
    );
    }
}

Please install the

npm i ngx-spinner

in you app.component.ts

<ngx-spinner></ngx-spinner>

Please refer:

https://www.npmjs.com/package/ngx-spinner