Valary o
Valary o

Reputation: 577

Service for progress bar in Vue

In Angular I usually have a special class which is in charge of the progress bar. I can intercept all HTTP requests and routing requests like this and it even works for GraphQL requests:

loading-indicator-service

import { Injectable } from '@angular/core';
import { Router, NavigationStart, NavigationCancel, NavigationEnd, NavigationError } from '@angular/router';
import { Subject, BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class LoadingIndicatorService {

  loading: BehaviorSubject<boolean> = new BehaviorSubject(false);

  constructor(private router: Router) {
    this.router.events.subscribe((event) => {

      switch (true) {
        case event instanceof NavigationStart: {
          this.show();
          break;
        }
        case event instanceof NavigationEnd:
        case event instanceof NavigationCancel:
        case event instanceof NavigationError: {

          this.hide();
          break;
        }


        default:
          break;
      }

    });
  }

  show() {
    this.loading.next(true);
  }

  hide() {
    this.loading.next(false);
  }
}

loading-interceptor-service

import { Injectable } from '@angular/core';
import { LoadingIndicatorService } from './loading-indicator.service';
import {
  HttpErrorResponse,
  HttpResponse,
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { finalize } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class LoadingInterceptorService implements HttpInterceptor {

  constructor(private loadingService: LoadingIndicatorService) { }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    this.loadingService.show();

    return next.handle(req)
      .pipe(
        finalize(() => this.loadingService.hide())
      );

  }
}

Is it possible to intercept HTTP GraphQL requests in Vue globally like in Angular so one place and one class in charge of this functionality? Because for now, I need to check loading for every request in each component and there in each component control the progress bar.

This is how I was trying to do that for now but apparently it doesn't work this way. I thought that $apollo is a global variable which controls all queries from all components

progress-bar.vue

<template>
  <div class="progress-bar-component" v-if="$apollo.loading">
    <div class="bar">{{this.$apollo.loading}}</div>
  </div>
</template>

<script>
export default {
  apollo: {}
};
</script>

<style>
.bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  /* height: 5px; */
  color: white;
  background-color: brown;
}
</style>

Thanks in advance!

Upvotes: 0

Views: 572

Answers (1)

tony19
tony19

Reputation: 138216

When setting up your VueApollo instance, you could pass a watchLoading hook that watches all queries:

const apolloProvider = new VueApollo({
  watchLoading (isLoading, countModifier) {
    loading += countModifier
    console.log('Global loading', loading, countModifier)
  },
  //...
})

The property is documented in Smart Query options:

watchLoading(isLoading, countModifier) is a hook called when the loading state of the query changes. The countModifier parameter is either equal to 1 when the query is loading, or -1 when the query is no longer loading.

Upvotes: 1

Related Questions