Cache an HTTP 'Get' service response in AngularJS?

AngularjsAjaxCachingHttp Get

Angularjs Problem Overview


I want to be able to create a custom AngularJS service that makes an HTTP 'Get' request when its data object is empty and populates the data object on success.

The next time a call is made to this service, I would like to bypass the overhead of making the HTTP request again and instead return the cached data object.

Is this possible?

Angularjs Solutions


Solution 1 - Angularjs

Angular's $http has a cache built in. According to the docs:

> cache – {boolean|Object} – A boolean value or object created with $cacheFactory to enable or disable caching of the HTTP response. See > $http Caching for more > information.

#Boolean value#

So you can set cache to true in its options:

$http.get(url, { cache: true}).success(...);

or, if you prefer the config type of call:

$http({ cache: true, url: url, method: 'GET'}).success(...);

#Cache Object# You can also use a cache factory:

var cache = $cacheFactory('myCache');

$http.get(url, { cache: cache })

You can implement it yourself using $cacheFactory (especially handly when using $resource):

var cache = $cacheFactory('myCache');

var data = cache.get(someKey);

if (!data) {
   $http.get(url).success(function(result) {
      data = result;
      cache.put(someKey, data);
   });
}

Solution 2 - Angularjs

I think there's an even easier way now. This enables basic caching for all $http requests (which $resource inherits):

 var app = angular.module('myApp',[])
      .config(['$httpProvider', function ($httpProvider) {
            // enable http caching
           $httpProvider.defaults.cache = true;
      }])

Solution 3 - Angularjs

An easier way to do this in the current stable version (1.0.6) requires a lot less code.

After setting up your module add a factory:

var app = angular.module('myApp', []);
// Configure routes and controllers and views associated with them.
app.config(function ($routeProvider) {
	// route setups
});
app.factory('MyCache', function ($cacheFactory) {
	return $cacheFactory('myCache');
});

Now you can pass this into your controller:

app.controller('MyController', function ($scope, $http, MyCache) {
	$http.get('fileInThisCase.json', { cache: MyCache }).success(function (data) {
		// stuff with results
	});
});

One downside is that the key names are also setup automatically, which could make clearing them tricky. Hopefully they'll add in some way to get key names.

Solution 4 - Angularjs

Check out the library angular-cache if you like $http's built-in caching but want more control. You can use it to seamlessly augment $http cache with time-to-live, periodic purges, and the option of persisting the cache to localStorage so that it's available across sessions.

FWIW, it also provides tools and patterns for making your cache into a more dynamic sort of data-store that you can interact with as POJO's, rather than just the default JSON strings. Can't comment on the utility of that option as yet.

(Then, on top of that, related library angular-data is sort of a replacement for $resource and/or Restangular, and is dependent upon angular-cache.)

Solution 5 - Angularjs

As AngularJS factories are singletons, you can simply store the result of the http request and retrieve it next time your service is injected into something.

angular.module('myApp', ['ngResource']).factory('myService',
  function($resource) {
    var cache = false;
    return {
      query: function() {
        if(!cache) {
          cache = $resource('http://example.com/api').query();
        }
        return cache;
      }
    };
  }
);

Solution 6 - Angularjs

angularBlogServices.factory('BlogPost', ['$resource',
    function($resource) {
        return $resource("./Post/:id", {}, {
            get:    {method: 'GET',    cache: true,  isArray: false},
            save:   {method: 'POST',   cache: false, isArray: false},
            update: {method: 'PUT',    cache: false, isArray: false},
            delete: {method: 'DELETE', cache: false, isArray: false}
        });
    }]);

set cache to be true.

Solution 7 - Angularjs

In Angular 8 we can do like this:

import { Injectable } from '@angular/core';
import { YourModel} from '../models/<yourModel>.model';
import { UserService } from './user.service';
import { Observable, of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})

export class GlobalDataService {

  private me: <YourModel>;

  private meObservable: Observable<User>;

  constructor(private yourModalService: <yourModalService>, private http: HttpClient) {

  }

  ngOnInit() {

  }


  getYourModel(): Observable<YourModel> {

    if (this.me) {
      return of(this.me);
    } else if (this.meObservable) {
      return this.meObservable;
    }
    else {
      this.meObservable = this.yourModalService.getCall<yourModel>() // Your http call
      .pipe(
        map(data => {
          this.me = data;
          return data;
        })
      );
      return this.meObservable;
    }
  }
}

You can call it like this:

this.globalDataService.getYourModel().subscribe(yourModel => {


});

The above code will cache the result of remote API at first call so that it can be used on further requests to that method.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGavriguyView Question on Stackoverflow
Solution 1 - AngularjsasgothView Answer on Stackoverflow
Solution 2 - AngularjsgspatelView Answer on Stackoverflow
Solution 3 - AngularjsJames SkempView Answer on Stackoverflow
Solution 4 - AngularjsXMLView Answer on Stackoverflow
Solution 5 - AngularjsRimianView Answer on Stackoverflow
Solution 6 - AngularjsHowardyanView Answer on Stackoverflow
Solution 7 - AngularjsRaghavView Answer on Stackoverflow