AngularJS $http.get cache not working - angularjs

After next(Route) to other page, come back it still call back the link.
How to cache JSON data from http call to optimize performance?
Try some solution but not working
$http.get(url, { cache: true}).success(...);
Any better solution to this?

Better way is to make CacheFactory as :-
var cache = $cacheFactory('myCache');
var data = cache.get(anyKey);
if (!data) {
$http.get(url).success(function(result) {
data = result;
cache.put(anyKey, data);
});
}

You can also use angular-data directive for caching. It allows you to specify where caching : local storage / session / memory, and you can set the time you want to keep your requests in cache.
http://angular-data.pseudobry.com/documentation/guide/angular-cache/index
To initialize the cache, add this code in a app.run() function :
DSCacheFactory('defaultCache', {
maxAge: 900000, // Items added to this cache expire after 15 minutes.
cacheFlushInterval: 6000000, // This cache will clear itself every hour.
deleteOnExpire: 'aggressive', // Items will be deleted from this cache right when they expire.
storageMode:'memory' // [default: memory] sessionStorage, localStorage
});
$http.defaults.cache = DSCacheFactory.get('defaultCache');
And then use it in your code like you did :
$http.get(url, { cache: true}).success(...);

I recommend to you download angular-cache! It is a very useful replacement for Angular's $cacheFactory
Inside a .run() block, define your cache:
.run(function (DSCacheFactory) {
DSCacheFactory("dataCache", {
storageMode: "localStorage",
maxAge: 720000, // time in milliseconds
deleteOnExpire: "aggressive"
});
}
Then inside your Service you can manage how to use your data, get it from Cache when it expires, make a new call and refresh data.
(function (){
'use strict';
app.factory('DataService', ['$http','$q','DSCacheFactory',DataService]);
function DataService($http, $q,DSCacheFactory){
self.dataCache= DSCacheFactory.get("dataCache");
self.dataCache.setOptions({
onExpire: function(key,value){
getData()
.then(function(){
console.log("Data Cache was automatically refreshed", new Date());
}, function(){
console.log("Error getting data. Putting expired info again", new Date());
// This line of code will be used if we want to refresh data from cache when it expires
self.dealerListCache.put(key,value);
});
}
});
function getData(){
var deferred = $q.defer(),
cacheKey = "myData",
dataFromHttpCall = self.dataCache.get(cacheKey);
if(dataFromHttpCall){
console.log("Found in cache");
deferred.resolve(dealersList);
} else {
$http.get('/api/dataSource')
.success(function (data) {
console.log("Received data via HTTP");
self.dataCache.put(cacheKey, data);
deferred.resolve(data);
})
.error(function () {
console.log('Error while calling the service');
deferred.reject();
});
}
return deferred.promise;
}
};
})();
That´s all!

Related

Custom cache for HTTP requests

I want to cache the response [i.e. parsed JSON response] of HTTP requests rather than the response itself. My data is big and gzipped so there is actually a fair performance hit decompressing this so would like to store the raw data itself.
Currently I am using a HTTP Interceptor for caching and TimeToLive mechanics described here alongside AngularJS' built in $cacheFactory.
So how can I, using an intercepter, stop the HTTP request and return my own response. Note I still plan on using $cacheFactory, I'd just manage my own data.
.factory('cacheInterceptor', ['$cacheFactory', function($cacheFactory) {
return {
request: function(config) {
if (config.cache) {
// if we have stored this request, return it, else let the request happen naturally and cache after
// Things I don't know:
// How to return existing cache data and prevent the reqeust from happening
// Cache the data I get back from a HTTP request
}
return config;
}
};
}])
I would preffer to inject this into your service and make your factory only handle the data recived/cached. This time I only created a service for you which holds the logic of HTTP / Cache switch. I think you will be able to create a factory to handle your data/states on your own.
.service('getService', ['$cacheFactory', '$http', '$q', function($cacheFactory, $http, $q) {
return {
request: function() {
function getData () {
var deferred = $q.defer();
if (angular.isUndefined($cacheFactory.get('getServiceData'))) {
$http({
'method': 'GET',
'url': 'someUrl'
}).then(function (result) {
$cacheFactory.put('getServiceData', result.data);
deferred.resolve(result.data);
});
} else {
deferred.resolve($cacheFactory.get('getServiceData'));
}
}
return getData();
},
flush: function () {
$cacheFactory.remove('getServiceData');
},
refresh: function () {
this.flush();
return this.refresh();
}
};
}]);
it's enough to add {cache: true} to the request options.
see the here
$http.get('some/url', {cache: true})
.then( ({data}) => data)

I set the service data,but after $http done, I cannot get the service data

My service define like this:
module.factory('portfolio',function(){
var data;
var selectedPort;
return{
getData: function(){
return data;
},
setData:function(portfolios){
data = portfolios;
},
getSelectedPort:function(){
return selectedPort;
},
setSelectedPort:function(portfolioDetail){
selectedPort = portfolioDetail;
}
}
});
And in my controller the code as follows:
module.controller('portfoliosController', function($scope,$http, alertService,stockService, userDataService, portfolio){
var req = {
method: 'get',
url: 'www.facebook.com',
headers: {
'Authorization': userDataService.getToken()
}
};
$http(req).then(function(reponse){
$scope.portfoliosPriceList = reponse['data'];
portfolio.setData($scope.portfoliosPriceList);
console.log(portfolio.getData())//At here,I can get the portfolio's data
}, function(){
alertService.setMessge("System maintenance , please try again later");
alertService.alert();
});
console.log(portfolio.getData())//At here, I cannot get the portfolio's data
});
the error is
Error: undefined is not an object (evaluating 'message.substr')
Anybody can help me to solve this problem?Actually, I really do not understand, why I cannot get the data outside the $http
The request that you do with the $http service is done asynchronously, so the callback that you pass to the .send is not immediately invoked.
The code that follows (the console.log) is executed just after the $http(req) call is made but before the callback is called when the request is responded.
Maybe you will understand better with an simpler example:
function portfoliosController() {
var data = 'Initial Data. ',
content = document.getElementById('content');
// setTimeout would be your $http.send(req)
// calledLater would be your .then(function() { ... })
setTimeout(function calledLater() {
data = 'Data coming from the server takes some time to arrive...';
content.innerHTML = content.innerHTML + data;
}, 1000);
content.innerHTML = content.innerHTML + data;
}
portfoliosController();
<div id="content">
This is because javascript is asynchronous, so the code:
portfolio.getData()
Is maybe executing before the data is returned from the service.
In this case, you should only use the data of the portfolio just after the request is complete (inside the .then() function of $http) or put a promise.
Here is the documentation for angular promises:
https://docs.angularjs.org/api/ng/service/$q

angularJS/ionic cannot read property 'then' of undefined

I'm adding Caching to my App everything works fine from caching data, getting it expired and re-cache. When I implemented the functionality of putting the same expired data in the cache again if there is no connection I get this error: Cannot read property 'then' of undefined
Here is the code of my controller:
.controller('ItemsCtrl', function($scope, $http, DSCacheFactory) {
//handle the catche to hold the items lits.
self.itemsCache = DSCacheFactory.get("itemsCache");
/*
*Function to re-refresh the cach after expire
*re-use the old cache if no internet connection available
*/
self.itemsCache.setOptions({
onExpire: function(key, value){
getItems()
.then(function(){
console.log("Items Cache was automatically refreshed", new Date());
}, function(){
console.log("Errorgetting data put expired item back in the cache", new Date());
});
}
});
function getItems(){
var cacheKey = "items",
itemsData = self.itemsCache.get(cacheKey);
if(itemsData){
// if data in the cache dont make HTTP calls.
console.log("Found Data in cache", itemsData);
//recive Data from the cache
$scope.items = itemsData;
}
else{//if no data in the catch make HTTP calls.
//HTTP request to get the items data.
$http.get('services/data.json')
.success(function(data){
console.log("Recived data via HTTP");
//caching the data recived from the http calls.
self.itemsCache.put(cacheKey, data);
$scope.items = data;
});
}//end of the else statment
}
getItems();
})
This didn't work I just didn't want to ruin the question.
.controller('ItemsCtrl', function($scope, $http, $q, DSCacheFactory) {
//handle the cache to hold the items lits.
self.itemsCache = DSCacheFactory.get("itemsCache");
/*
*Function to re-refresh the cache after expire
*re-use the old cache if no internet connection available
*/
self.itemsCache.setOptions({
onExpire: function(key, value){
getItems()
.then(function(){
console.log("Items Cache was automatically refreshed", new Date());
}, function(){
console.log("Errorgetting data put expired item back in the cache", new Date());
});
}
});
function getItems(){
var deferred = $q.defer(),
cacheKey = "items",
itemsData = self.itemsCache.get(cacheKey);
if(itemsData){
// if data in the cache dont make HTTP calls.
console.log("Found Data in cache", itemsData);
//receive Data from the cache
$scope.items = itemsData;
deferred.resolve(itemsData);
}
else{//if no data in the catch make HTTP calls.
//HTTP request to get the items data.
$http.get('services/data.json')
.success(function(data){
console.log("Received data via HTTP");
//caching the data received from the http calls.
self.itemsCache.put(cacheKey, data);
$scope.items = data;
deferred.resolve(data);
});
}//end of the else statement
}
getItems();
})
The function getItems isn't returning anything - it looks like you meant to return a promise so it should be something like below.
When you find the item in the cache you can use $q.when to create a promise that's already resolved when the parameter isn't a promise.
When you don't find it, you can return the chained promise from $http.get.
.controller('ItemsCtrl', function($scope, $http, DSCacheFactory, $q) {
//handle the cache to hold the items list.
self.itemsCache = DSCacheFactory.get("itemsCache");
/*
*Function to re-refresh the cache after expire
*re-use the old cache if no internet connection available
*/
self.itemsCache.setOptions({
onExpire: function(key, value){
getItems()
.then(function(itemsData){
console.log("Items Cache was automatically refreshed", new Date());
}, function(){
console.log("Error getting data put expired item back in the cache", new Date());
});
}
});
function getItems(){
var cacheKey = "items",
itemsData = self.itemsCache.get(cacheKey);
if(itemsData){
// if data in the cache dont make HTTP calls.
console.log("Found Data in cache", itemsData);
//receive Data from the cache
$scope.items = itemsData;
return $q.when(itemsData);
}
else{//if no data in the catch make HTTP calls.
//HTTP request to get the items data.
return $http.get('services/data.json')
.success(function(data){
console.log("Received data via HTTP");
//caching the data received from the http calls.
self.itemsCache.put(cacheKey, data);
$scope.items = data;
return data;
});
}//end of the else statement
}
getItems();
})

Cancelling a request with a $http interceptor?

I'm trying to figure out if it is possible to use a $http interceptor to cancel a request before it even happens.
There is a button that triggers a request but if the user double-clicks it I do not want the same request to get triggered twice.
Now, I realize that there's several ways to solve this, and we do already have a working solution where we wrap $http in a service that keeps track of requests that are currently pending and simply ignores new requests with the same method, url and data.
Basically this is the behaviour I am trying to do with an interceptor:
factory('httpService', ['$http', function($http) {
var pendingCalls = {};
var createKey = function(url, data, method) {
return method + url + JSON.stringify(data);
};
var send = function(url, data, method) {
var key = createKey(url, data, method);
if (pendingCalls[key]) {
return pendingCalls[key];
}
var promise = $http({
method: method,
url: url,
data: data
});
pendingCalls[key] = promise;
promise.finally(function() {
delete pendingCalls[key];
});
return promise;
};
return {
post: function(url, data) {
return send(url, data, 'POST');
}
}
}])
When I look at the API for $http interceptors it does not seem to be a way to achieve this. I have access to the config object but that's about it.
Am I attempting to step outside the boundaries of what interceptors can be used for here or is there a way to do it?
according to $http documentation, you can return your own config from request interceptor.
try something like this:
config(function($httpProvider) {
var cache = {};
$httpProvider.interceptors.push(function() {
return {
response : function(config) {
var key = createKey(config);
var cached = cache[key];
return cached ? cached : cached[key];
}
}
});
}
Very old question, but I'll give a shot to handle this situation.
If I understood correctly, you are trying to:
1 - Start a request and register something to refer back to it;
2 - If another request takes place, to the same endpoint, you want to retrieve that first reference and drop the request in it.
This might be handled by a request timeout in the $http config object. On the interceptor, you can verify it there's one registered on the current request, if not, you can setup one, keep a reference to it and handle if afterwards:
function DropoutInterceptor($injector) {
var $q = $q || $injector.get('$q');
var dropouts = {};
return {
'request': function(config) {
// I'm using the request's URL here to make
// this reference, but this can be bad for
// some situations.
if (dropouts.hasOwnProperty(config.url)) {
// Drop the request
dropouts[config.url].resolve();
}
dropouts[config.url] = $q.defer();
// If the request already have one timeout
// defined, keep it, othwerwise, set up ours.
config.timeout = config.timeout || dropouts[config.url];
return config;
},
'requestError': function(reason) {
delete dropouts[reason.config.url];
return $q.reject(reason);
},
'response': function(response) {
delete dropouts[response.config.url];
return response;
},
'responseError': function(reason) {
delete dropouts[reason.config.url];
return $q.reject(reason);
}
};
}

How to defer loop wrapped $http get request in angular js?

I have a function that checks for for records and if they exist it downloads them for each item. This is a function that happens with in a loop so there can me many records. I thought that I was using $Q properly to deffer each $http request to wait for one after each other so they do not all happen at the same time but they all fire at the same time still.
I have seen $q.defer(); but do not understand how to use it in my implementation. How would this be written properly deferring each call until the one before is complete?
CheckRecords: function(obj) {
var promise;
var promises = [];
if (obj.BD.img == 'checkedRecord') {
var objBDUrl = 'services/GetSurveyBD/?id=' + obj.BD.ID;
promise = $timeout(function(){
$http.get(objBDUrl, { cache: true }).then(function(response) {
obj.BD.ID = obj.BD.ID;
obj.BD.data = response.data;
});
}, 250);
promises.push(promise);
}
if (obj.MR.img == 'checkedRecord') {
var objMRUrl = 'services/GetMR/?id=' + obj.MR.ID;
promise = $timeout(function(){
$http.get(objMRUrl, { cache: true }).then(function(response) {
obj.MR.ID = obj.MR.ID;
obj.MR.data = response.data;
});
}, 250);
promises.push(promise);
}
$q.all(promises).then(function(){
return obj;
});
}
The function $q.all just ensures that all requests completed, the requests are still executed immediately, but their results are deferred. If you want to control the execution order you, do your requests in the result function.
$q
- service in module ng
A service that helps you run functions asynchronously, and use their return values (or exceptions) when they are done processing.

Resources