angularJS/ionic cannot read property 'then' of undefined - angularjs

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();
})

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)

console service response inside controller

i have written a service with take parameter on the basis of which it response me with the response of http request.
this.getPaymentDueDetails=function(date){
this.getfromRemote('paymentdue/'+btoa(date))
.success(function(response){
return response;
})
.error(function(response){
return false;
})
}
getfromRemote is my another service which make http request
now i am trying to get the response of this service call inside my controller function
$scope.callDueReports=function(blockNum){
var data;
data=myAngService.getPaymentDueDetails('2015-04-20');
console.log(data);
}
its quite obvious that i wont get any thing in data as the page loads initially but i want the result of getPaymentDueDetails int it.
Please modify your service to return the promise like below.
this.getPaymentDueDetails = function(date) {
return this.getfromRemote('paymentdue/' + btoa(date));
};
And in controller check if the promise is resolved.
$scope.callDueReports = function(blockNum) {
var data;
myAngService.getPaymentDueDetails('2015-04-20').then(function(dataFromService) {
data = dataFromService;
console.log(data);
})
.catch(function(response) {
console.error('error');
});
};

Get data synchronously when cached or get it async when unavailable

I have an AngularJS app that uses routing and views. When a particular view is loaded and controller instantiates I have to prepare some $scope model data. This data can be provided by a dependent service or when service doesn't have it, I make an async call to get it from the server.
When I finally do have this data I have to change it a bit and then put it on my $scope.
This I think perfectly falls into deferred/promise API. Getting data from the service is done using $resource service instance and is a promise already. The only problem I'm having is converting my synchronous code to a deferred/promise pattern.
Question
How can I change my synchronous code processing to become async so my function that provides data always returns a promise which would be immediately resolved when using sync code and after a while when asynchronously calling my server?
So process:
try getting data synchronously
if sync failed, get it async
success/fail
data available => manipulate it
data unavailable (either way) => reset state
What I tried
var getData = function() {
var defer = $q.defer();
defer.promise
.then(function () {
// return cached item
return dataCacheService.get("dataKey");
})
.then(function(data) {
// cache returned data?
if (!data)
{
// no? get it from server returning a promise
return dataResource.get({
set: "models",
id: $routeParams.id
});
}
})
.then(function (data) {
// server returned data?
if (!!data) // <= PROBLEM!!! This is not null, but is a Resource with unresolved promise?
{
// yes? fine. manipulate it
delete data.details;
delete data.type.description;
$scope.lists.set(data.type);
return data;
}
// no data. sorry...
$scope.resetType();
})
// something went wrong
.catch($scope.resetType);
// initiate deferred execution
defer.resolve();
return defer.promise;
}
...
$scope.model = {
item: getData()
};
You can make your service such that it always returns a promise, if the data is available it will return the promise immediately otherwise after a REST call. For example your service might look like:
var dataThatMayOrMayNotBeAvailable=null;
var getDataThatMayOrMayNotBeAvailable=function(){
var deferred = $q.defer();
if(dataThatMayOrMayNotBeAvailable){
deferred.resolve(dataThatMayOrMayNotBeAvailable);
}else{
$http({...}).success(function(data){
dataThatMayOrMayNotBeAvailable=data;
deferred.resolve(data);
});
}
return deferred.promise;
}
Usage:
getDataThatMayOrMayNotBeAvailable().then(function(data){
console.log(data);
})

AngularJS $http.get cache not working

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!

Handling Errors in Angularjs

Folks,
I have written a service that fetches data from my server in the following fashion:
myApp.factory('CommonHttpService', function($http, $q){
var myUrl;
return{
query: function(tableName){
//Forming the URl
myUrl = baseUrl + "?table=" + tableName;
// Create a deferred object
var deferred = $q.defer();
//Calling web api to fetch all rows from table
$http.get(myUrl).success(function(data){
deferred.resolve(data);
}).error(function(){
// Sending a friendly error message in case of failure
deferred.reject("An Error occured while fetching items");
});
// Returning the promise object
return deferred.promise;
}});
My Controller calls it like this:
// Get entire list
CommonHttpService.query(tableName).then(function(data) {
$scope.list = data;
});
So my question is, in this entire scheme of things I am not sure HOW or WHERE to handle errors.
Does the error get handled in deferred.reject().. if so how ?
Or does it get handled after the .then() in the controller.
Ideally I should be displaying some sort of message to the user like "No data found" and itnernally sending the error details to the admin or something
Those who have done, this before and have any bits of advice kindly pass them ON.
Thanks in advnace.
Then expects two function first is sucess and second is failure
CommonHttpService.query(tableName).then(function(data) {
$scope.list = data;
},function(error){
alert("error")
});
You should directly return $http.get which also returns a promise
--Refactoring ---
myApp.factory('CommonHttpService', function($http, $q){
var myUrl;
return{
query: function(tableName){
myUrl = baseUrl + "?table=" + tableName;
//$http.get also returns a promise
return $http.get(myUrl)
}});
CommonHttpService.query(tableName).then(function(data) {
$scope.list = data;
},function(error){alert(error});

Resources