How to display a spinner during a request?

Viewed 167

There is application that sends http request. Special service stores state of the spinner. To do this it uses BeahivoirSubject. Interceptor set spinners state to true before any http request. When http request is ended interceptor set spinners state to false.

However, spinner is not displayed at all. This is the problem. Please help to display a spinner during a http request.

I deliberately add artificial 2000ms delay to each http request using RXJS capabilities.

LIVE DEMO

Interceptor code:

@Injectable()
export class MyInterceptor implements HttpInterceptor {
  constructor(private globalService: GlobalService) {}

  intercept(
    request: HttpRequest<unknown>,
    next: HttpHandler
  ): Observable<HttpEvent<unknown>> {
    request = request.clone({
      setHeaders: { Authorization: `Bearer 123` }
    });

    this.globalService.setSpinnerState(true);

    return next
      .handle(request)
      .pipe(finalize(() => this.globalService.setSpinnerState(false)));
  }
}

Request service code:

@Injectable({
  providedIn: "root"
})
export class ApiService {
  constructor(private http: HttpClient) {}

  getData() {
    console.log("start request");
    return this.http
      .get("https://jsonplaceholder.typicode.com/todos/1")
      .pipe(delay(2000))
      .subscribe((res: any) => {
        console.log(res);
        console.log("end request");
      });
  }
}

Spinner service code:

@Injectable({
  providedIn: "root"
})
export class GlobalService {
  private isShowSpinner = new BehaviorSubject(false);

  constructor() {}

  spinner() {
    return this.isShowSpinner.asObservable();
  }

  setSpinnerState(state: boolean) {
    return this.isShowSpinner.next(state);
  }
}

Component code:

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  isShowSpinner: boolean;
  constructor(
    private apiService: ApiService,
    private globalService: GlobalService
  ) {
    this.apiService.getData();
    this.globalService.spinner().subscribe((state: boolean) => {
      this.isShowSpinner = state;
    });
  }
}
1 Answers

Your approach is generally correct. In the example you provided I could see the spinner for a short period of time. However the way you implemented the artificial delay for an api call is wrong. next.handle only waits for the http call to be finished so as soon as it happened the setSpinnerState functions has been called with false as parameter. If you want to see the delay for testing purposes you should put the delay into the interceptor like this

 return next.handle(request).pipe(
      delay(2000),
      finalize(() => this.globalService.setSpinnerState(false))
    );

and of course remove it from the api.service.

Related