Creating an Http interceptor in Ionic 3 and Angular 4 to display a loading indicator for every API request

One of my current challenges involves creating a custom HTTP interceptor to manage loading and other additional functions efficiently. Manually handling loading for each request has led to a considerable increase in code.

The issue at hand: The loader is being activated with every request, but the loading.dismiss() function does not seem to work as expected. Despite no errors, the loading spinner remains active.

Here's an overview of my configuration:

HTTP Interceptor:

@Injectable()
export class MyHttpWrapper extends Http {
  private loading: any;

  constructor(connectionBackend: ConnectionBackend, requestOptions: RequestOptions,private loadingCtrl: LoadingController) {
    super(connectionBackend, requestOptions);
  }

  public get(url: string, options?: RequestOptionsArgs): Observable<Response> {
    this.showLoader();

    return super.get(url, this.getRequestOptionArgs(options))
      .finally<Response>(() => {
        this.hideLoader();
      });
  }
  // Other methods omitted for brevity

app.module.ts

export function httpInterceptorFactory(xhrBackend: XHRBackend, requestOptions: RequestOptions, loadingCtrl: LoadingController) {
  return new MyHttpWrapper(xhrBackend, requestOptions, loadingCtrl);
}
    @NgModule({
      declarations: [
        MyApp
      ],
      imports: [
        BrowserModule,
        HttpModule,
        IonicModule.forRoot(MyApp),
        IonicStorageModule.forRoot()
      ],
      bootstrap: [IonicApp],
      entryComponents: [
        MyApp
      ],
      providers: [
        StatusBar,
        SplashScreen,
        {provide: ErrorHandler, useClass: IonicErrorHandler},
        {provide: APP_CONFIG, useValue: AppConfig},
        {
          provide: Http,
          useFactory: httpInterceptorFactory,
          deps: [XHRBackend, RequestOptions, LoadingController]
        }
      ]
    })
    export class AppModule {}

UPDATE:

After attempting to integrate a simple service (utilized within MyHttpWrapper), the problem persists without any changes in behavior. It seems like the issue lies elsewhere.

@Injectable()
export class LoadingService {
  private loading:any;

  constructor(private loadingCtrl: LoadingController) {

  }

  show() {
    if(!this.loading){
      this.loading = this.loadingCtrl.create({
        dismissOnPageChange: true
      });
    }
    this.loading.present();
  }
  hide() {
    if (this.loading) {
      this.loading.dismiss();
    }
  }
}

Answer №1

I have implemented a custom HTTP interceptor in my Ionic 3 application.

Below is the code for loader.ts

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import { LoadingController } from 'ionic-angular';

@Injectable()
export class LoaderProvider {

  constructor(public http: Http, public loadingCtrl: LoadingController) {

  }

  loading: any = this.loadingCtrl.create({
    content: "Please wait..."
  })

  show() {
    this.loading.present();
  }

  hide() {
    this.loading.dismiss();
  }


}

This code snippet represents the implementation of an HTTP interceptor.

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/Rx';

import { LoaderProvider } from '../loader/loader';

/*

Ionic 3 HTTP interceptor
Author: iSanjayAchar (@iSanjayAchar) <<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ef9c8e81858e968c878e9daf88828e868389cea18285">[email protected]</a>>

*/

@Injectable()

export class httpService {

  baseUrl: string = 'https://yourbaseurl.in'

  constructor(public http: Http, private loader: LoaderProvider) {

  }

  get(url) {
    this.loader.show();
    return this.http.get(this.baseUrl + url)
      .map(resp => resp.json())
      .finally(() => {
        this.loader.hide();
      });
  }

  post(url, body) {
    this.loader.show();
    return this.http.post(this.baseUrl + url, body)
      .map(resp => resp.json())
      .finally(() => {
        this.loader.hide();
      });
  }

  put(url, body) {
    this.loader.show();
    return this.http.put(this.baseUrl + url, body)
      .map(resp => resp.json())
      .finally(() => {
        this.loader.hide();
      });
  }

  delete(url) {
    this.loader.show();
    return this.http.delete(this.baseUrl + url)
      .map(resp => resp.json())
      .finally(() => {
        this.loader.hide();
      });
  }

  patch(url, body) {
    this.loader.show();
    return this.http.patch(this.baseUrl + url, body) 
      .map(resp => resp.json())
      .finally(() => {
        this.loader.hide();
      });
  }
}

To use the custom HTTP interceptor, import it instead of http in your components as demonstrated below

import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { Http, Headers, RequestOptions } from '@angular/http';
import { ToastController } from 'ionic-angular';
import 'rxjs/add/operator/map';
import { AlertController } from 'ionic-angular';
import { httpService } from '../../providers/http/http';

/**
 * Generated class for the LoginPage page.
 *
 * See http://ionicframework.com/docs/components/#navigation for more info
 * on Ionic pages and navigation.
 */

@IonicPage()

@Component({
  selector: 'page-login',
  templateUrl: 'login.html',
})

export class LoginPage {
  isLoginIn: boolean = false;

  user: any = {
    email: '',
    password: ''
  }


  constructor(private http: httpService, private toast: ToastController) {

  }

 login() {

    this.http.post('/api/v1/login/', this.user)
      .subscribe(resp => {

          //Your logic

      }, err => {

         //Your logic

      }
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Dynamic bullseye displayed on a Vis.js network node

I am currently utilizing Vis.js to create network diagrams. I am interested in adding a notification feature where when an AJAX update is received for a specific node, the canvas will move that node to the center (which Vis.js can already do). Following th ...

Javascript object attributes

Could you retrieve the value of one object property based on the value of another property? For instance, in an SQL query, is it possible to fetch the id from the object where the object.name equals "somename"? I am trying to obtain the id of a particula ...

enable jQuery timer to persist even after page refresh

code: <div class="readTiming"> <time>00:00:00</time><br/> </div> <input type="hidden" name="readTime" id="readTime"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script&g ...

How to make a node_module global with the power of Webpack 2

I'm currently utilizing a package in an Angular project that can be found at the following link: https://github.com/pablojim/highcharts-ng One of the requirements for this package is that highcharts needs to be included as a global dependency by add ...

The attempt to connect with react-native-fetch-blob has not been successful

How do I resolve the issue of displaying a PDF from my assets folder in an Expo, React Native project using react-native-pdf? While scanning folders for symlinks, encountered an error with RNFetchBlob library in my project directory. The automatic linki ...

Tips for showing HTML content in an Angular UI grid

I've been attempting to showcase HTML within the grid by checking out this resource: Add html link in anyone of ng-grid However, my attempts led me to this code snippet: var app = angular.module('myApp', ['ngGrid']); ...

Struggling with running my React App as I'm encountering some errors

Check out the code on Github: https://github.com/bhatvikrant/IndecisionApp I have already run npm i and then executed yarn run dev-server, utilizing webpack. My operating system is MacOs. I have also created the .babelrc file. The issue I encountered aft ...

I'm encountering an issue with Regex.test

When working with the following JavaScript code... $.post(url, data, function (json) { var patt = new RegExp('/^\[{"dID":/'); if (patt.test(json)) { //output json results formatted } else { //error so o ...

form_not_submitting_ajax

In the app I'm working on, I have a form that is defined in the following manner: = form_with model: project, remote: true, method: :put do |f| = f.select :selected_draw, options_for_select(project.draws.pluck(:number, :id), draw.id), {}, class: &a ...

An onClick event is triggered only after being clicked twice

It seems that the onClick event is not firing on the first click, but only works when clicked twice. The action this.props.PostLike(id) gets triggered with a delay of one click. How can I ensure it works correctly with just one click? The heart state togg ...

"The controller seems to always return an 'undefined' value for the Angular

Within my project, I have implemented ui-view with the following structure: <main class="content"> <div class="inner" ng-controller="OrderPageController"> <div ui-view="main-info"></div> <div ui-view="comment ...

Ensure that nested DTO objects are validated using class validator

Currently, I am utilizing the class validator to validate incoming data which comprises an array of objects that need validation individually. An issue that has arisen is that despite inputting everything correctly, I keep encountering errors. It appears ...

Tips for preventing the unmounting of child components while utilizing JSX's map function

This is a condensed version of a question I previously asked. Hopefully, it's clearer and more comprehensible. Here is a simple application with 3 input fields that accept numbers (disregard the ability to enter non-numbers). The app calculates the s ...

Encountering an issue while trying to set up Gulp js on my

I'm facing an issue while trying to set up Gulp js on my system. It seems like the installation is incomplete as running gulp -v in powershell gives the following output: [12:43:04] CLI version 1.3.0 [12:43:04] Local version 3.9.1 However, when att ...

What is the best way to smoothly move a fixed-size div from one container to another during a re-render process?

Introduction Anticipated change Similar, though not identical to my scenario: Situation 0: Imagine you have a container (chessboard with divs for game pieces) and a dead-pieces-view (container for defeated pieces). The positioning of these containers i ...

Activate the action using the onclick interaction

window.addEventListener(mousewheelEvent, _.throttle(parallaxScroll, 60), false); My current setup involves an event listener that responds to a mousewheelEvent by executing a function. However, when attempting to directly trigger this function on a separa ...

Anchor no longer follows endpoint after Anchor ID is modified following creation - JSPlumb

I am currently developing an editor that involves placing shapes on a canvas and assigning IDs to them. When a shape is placed, endpoints are automatically created and attached to the shape using its ID as an anchor. //Function responsible for adding en ...

ES6 Conditional Import and Export: Leveraging the Power of Conditional

Looking to implement a nested if else statement for importing and exporting in ES6? In this scenario, we have 2 files - production.js and development.js which contain keys for development and production code respectively. Additionally, there is another fil ...

Troubleshooting the "missing checks.state argument" error in AUTH0 debugging

I recently launched my new NextJs blog application at on Vercel, but I'm encountering some issues with getting auth0 to function properly. Upon clicking the login button located in the top right corner of the screen, users are redirected to auth0 to ...

Discovering the potential of utilizing an array transmitted by Node/Express on the server-side and integrating it into Google Maps on the client-side

When attempting to set up clustering markers on Google Maps, I encountered a challenge. Client-Side <script> // Code snippet from Google Map docs function initMap() { // Array of locations const locations = [ { lat: -31.56391, lng: 147.15 ...