How do I completely disable internal caching in Ionic 3?

I have struggled for a long time now with caching.

Is there an option I can place in my app.component.ts to completely disable caching?

My http requests never update my view no matter what I do. I have tried IonViewDidEnter, NgZone and various other solutions. Nothing works for me.

I hope someone has an idea of how to change this.

Have you tired creating a ā€˜mockā€™ service and seeing if it functions as you expect?

For example:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { Observable } from 'rxjs/Observable';

import { Venue } from '@core/models';

@Injectable()
export class MockVenuesService  {

  private readonly URL = 'assets/data/venues/venues.json';

  constructor(protected httpClient: HttpClient) {}

  public list(): Observable<Venue[]>   {
    return this.httpClient.get<Venue[]>(this.URL);
  }

}

I havenā€™t tried using a mock service but I have tried various http requests. Iā€™m using Angular 4.0.3 and therefore the older http client.

Could that have an effect?

It works perfectly to get the data the first time. There is just no update after that.

My service:

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';

@Injectable()
export class ItemApi {

  constructor(private http: Http) { }

  /**
   * @description get a number of posts
   * @param number 
   */
  getItems(number) {
    return new Promise(resolve => {
      this.http.get('www.website.com/posts?per_page=' + number)
        .subscribe(res => resolve(res.json()));
    });
  }

  /**
   * @description get posts in one category
   * @param id 
   */
  getCategory(id) {
    return new Promise(resolve => {
      this.http.get('www.website.com/posts?categories=' + id)
        .subscribe(res => resolve(res.json()));
    });
  }

My page:

import { Component, NgZone, ChangeDetectorRef, ApplicationRef } from '@angular/core';
import { NavController, NavParams, LoadingController } from 'ionic-angular';
import { Http } from '@angular/http';
import { StatusBar } from '@ionic-native/status-bar';
import { Keyboard } from '@ionic-native/keyboard';

// Import pages to allow links to the page
import { SingleItem } from '../../pages/single-item/single-item';

// Service import for items
import { ItemApi } from '../../services/service';

@Component({
  selector: 'page-list',
  templateUrl: 'list.html',
  providers: [Http]
})
export class ListPage {

  items: any;
  posts: any;
  searchQuery: string = '';
  checkStatus: any;

  constructor(
    public navCtrl: NavController,
    public params: NavParams,
    private itemApi: ItemApi,
    public loadingController: LoadingController,
    private statusBar: StatusBar,
    public keyboard: Keyboard,
    public zone: NgZone,
    public changeDetectorRef: ChangeDetectorRef,
    public applicationRef: ApplicationRef
  ) { }

  /**
   * @description life cycle event that fires right before the view becomes the active view.
   */
  ionViewWillEnter() {
    
    // Make the statusbar black
    this.statusBar.styleDefault();

    // show searchbar
    this.checkStatus = true;
  }

  /**
   * @description this is where the data loads from the service. This event always fires. It is a way of stopping caching in the app.
   */
  ionViewDidEnter() {
      this.loadItems();
  }

  /**
   * @description loads all items
   */
  loadItems() {
    
    // Create the loader
    let loader = this.loadingController.create({
      content: "Getting items.."
    });
    loader.present();

    // Get the most recent 100 posts
    this.itemApi.getItems(100).then(data => {
      loader.dismiss();

      // update data
      this.zone.run(() => {
        this.posts = data
      });

      this.initializeItems();
    });

  }

/**
   * @description set the new data equal to the items returned. This happens in an Angular zone to update the view with new items.
   */
  initializeItems() {
    // The data is reset to all items
    this.items = this.posts;
  }

Iā€™m suggesting that you create a ā€˜mockā€™ service in order to help you identify the actual issue. It may not be cache related at all.

Remember you can use setTimeout() to simulate network latency:


    setTimeout(() => {

      this.venuesService.listLocations(this.currentPosition).subscribe(data => {

        data.sort((a, b) => {
          return a.name < b.name ? -1 : 1;
        });
        this.items = data;
      });

    }, 1500);

BTW, why are you using:

import { Http } from '@angular/http';

You should be using:

import { HttpClient } from '@angular/common/http';

See: https://angular.io/guide/http

Alright. I will try to create a mock service to help identify the issue. I will try with the newer HttpClient and simulating network latency.

However, when I run my project in the browser and disable cache it actually works and gets the newest item in the list. This is why Iā€™m thinking its related to the cache. When I build on iOS it never updates the view with new data.

With this happening, is it still not related to caching?

Are you sure itā€™s not just erroring out? You currently swallow up any errors that occur due to explicit promise creation.

I might be. I have tried various things but none have worked.
Do you any specific solution how not to swallow up errors?
How do I avoid the explicit promise?

this.http.get('www.website.com/posts?per_page=' + number)
.pipe(map(res => res.json()))
.toPromise();

Then wherever you use the promise add a .catch() block.

  1. To force cache from being used, use a fake argument in your query string with a different value each call. For example:
    let rand = Math.random();
    this.http.get(ā€˜www.website.com/posts?categories=ā€™ + id+ā€™&force=ā€™+rand)
  2. Your initializeItems, although the comment says ā€œā€¦happens in an Angular zoneā€¦ā€, you donā€™t call this function from within the zone ( only this.posts assignment will be in the zone ).
  3. The call to your backend is always with same parameters ( 100 ), is it possible that you get the same results each time?
1 Like

I have tried various different things since the suggestions in this thread.

The thing that finally worked for me was your suggestion with the fake argument in the http call. Now I change the number on every http request to force the application to get potential new data.

I donā€™t understand how this is the only solution as several other solutions have suggested both IonViewDidEnter, NgZone and various other designs. However, nothing has worked for me. I also tested the network latency suggestion with setTimeout and this did not work either.

Everything I have done points toward some sort of caching as I the application retrieves the newest item when I disable the browser cache. But something on my device (ios) must be caching the http requests or something similar to prevent displaying new data. I have also removed the service worker to make sure it was not causing http request cache.

Thank you all for your suggestions and patience.

1 Like

-> Then wherever you use the promise add a .catch() block

Did you add a catch block to your code, for example:

  this.authService.signInWithEmailAndPassword(email, password).then(() => {
    this.navCtrl.setRoot('TabsPage');
  })
  .catch((error) => {
    this.logger.error('SignInPage signIn() error code: ' + error.code + ' error.message: ' + error.message);
  });

I do have exactly the same problem. It only works with fack argument but this is not an ellegant solution since I have hundreds of api calls throughout my application and I have to change all those API endpoints accordingly unnecessarily.

I hope someone finds a better solution.

I finally could figure out this problem using Http Headers. I added below headers to all my requests.

const headers = new Headers();
headers.append(ā€˜Cache-controlā€™, ā€˜no-cacheā€™);
headers.append(ā€˜Cache-controlā€™, ā€˜no-storeā€™);
headers.append(ā€˜Expiresā€™, ā€˜0ā€™);
headers.append(ā€˜Pragmaā€™, ā€˜no-cacheā€™);

let requestOptions = new RequestOptions({headers: headers}

this.http.get(${this.baseUrl}/api/manager/accounts/?mobile=${mobile}, requestOptions)

Now, everything is working as expected!

4 Likes

This is an old topic but still useful for me. I have tried both of the solution from @esfand55 and @Roye but the http request is blocked by CORS policy, is there a way to avoid this error? without using above methods wonā€™t trigger this error. Thanks!

Never mind! I just use this, worked for me: url?random="+ (new Date()).getTime()