AngularJS how to caching request with $http and $cacheFactory - angularjs

I have the next problem
I'm trying to caching a get request with $http but seems not working, the cache variable always get undefined
Sample code:
myApp.factory("sample", ["$http", "$q", "$cacheFactory", sample]);
function sample($http, $q, $cacheFactory) {
function getData() {
var url = "http://whatever ...";
return $http.get(url, {
params: {
Id: 10
},
cache: true
})
.then(function(response) {
// trying to get the cached data
var cache = $cacheFactory.get("$http");
var data = cache.get(url); // undefined -> ??
return response.data;
})
.catch(function(error) {
return $q.reject(error);
});
}
return {
getData: getData
};
}

The problem was with the URL which you are passing to get the cache.
This works.
myApp.factory("sample", ["$http", "$q", "$cacheFactory", sample]);
function sample($http, $q, $cacheFactory) {
function getData() {
var url = "http://whatever ...";
return $http.get(url, {
params: {
Id: 10
},
cache: true
})
.then(function(response) {
// trying to get the cached data
var cache = $cacheFactory.get("$http");
var data = cache.get(url+"?id=10"); // cacheFactory will store the cache data with full URL including params so your key should have the params
return response.data;
})
.catch(function(error) {
return $q.reject(error);
});
}
return {
getData: getData
};
}
cacheFactory will store the cache data with full URL including params so your key should have the params.
cache.get(url+"?id=10");

Related

Angularjs - Editing arrays returned from http get url

I have this array I am getting through the following method:
var url= *url defined here*;
$scope.ViewProfile = function () {
$http.get(url)
.success(function (response) {
$scope.ProfileList = response;
$scope.FavNumbers = $scope.ProfileList[0].FavNumbers;
})
.error(function () {
});
}
I am required to edit the Fav Numbers list on the UI. and post it back to another url through http post url method. What I am stuck is with the concept of asynchronous calls, due to which I am unable to retrieve the favorite numbers list to be available for editing. Please help!
I have tried a method of using promises as follows:
app.factory('myService', function($http) {
var myService = {
async: function(url) {
var promise = $http.get(url).then(function (response) {
console.log(response);
return response.data;
});
// Return the promise to the controller
return promise;
}
};
return myService;
});
In my controller I am doing:
angular.module('JuryApp').controller('mycontroller', ['myService', function (myService) {
myService.async(url).then(function(d) {
$scope.data = d;
});
app.controller('MainCtrl', function( myService,$scope) {
// Call the async method and then do stuff with what is returned inside our own then function
myService.async().then(function(d) {
$scope.data = d;
});
});
But I keep getting the error 'd is not defined'. It keeps giving an error of some sort, where the debugger goes into an infinite loop or something.
You are overcomplicating it, I think. Async calls are actually pretty simple:
You're service:
app.factory("myService", ["$http", function($http) {
var MyService = {
getData: function(url) {
return $http.get(url); //$http returns a promise by default
}
};
return MyService;
})];
Your controller:
angular.module('JuryApp').controller('mycontroller', ['myService', function (myService) {
$scope.FavNumbers = [];
var url = "http://my.api.com/";
myService.getData(url).then(function(response) {
$scope.FavNumbers = response.data[0].FavNumbers;
});
}]);
That's all that you need to do.

Ionic angular service only return data after controller call

I have a service that do two $http.get to get data from two source and concat into an array and return it to controller.
angular.module('starter.controllers').factory('GetDataList', function ($http) {
var arrDataList = [];
var postData1 = {
"param": "1"
};
var postData2 = {
"param": "2"
};
$http({
method: 'GET',
url: 'https://localhost/search',
data: postData1
})
.then(function (items) {
debugger
arrDataList = arrDataList.concat(items.data.list);
});
$http({
method: 'GET',
url: 'https://localhost/locate',
data: postData2
})
.then(function (items) {
debugger
arrDataList = arrDataList.concat(items.data.list);
});
return {
getAPIData: function () {
debugger
return arrDataList;
}
};
});
In my controller, I call it like this:
$scope.GetList = function () {
debugger
$scope.item = GetDataList.getAPIData();
$scope.$broadcast('scroll.infiniteScrollComplete');
}
When I use the debugger in console, I notice that
1) getAPIData() will be called first but it has data in it
2) Next debugger triggered at the controller which GetDataList.getAPIData(); does not return any data for $scope.Item
3) The last debugger reach $http call which return the data correctly as I observed in the console. But it never reach the controller side afterwards so no data is being displayed in the mobile app
I read about the natural behavior of angular async call so this seems to be normal. But in my case, what should I do to ensure that the data could reach the controller?
Many thanks
To achieve that without loosing performance, you should use $q.all(), so it will keep your request async and it will return the data once all the promises are resolved. Don't try a synchronic approach because that will reduce your performance.
You can use it like this:
Your factory:
app.factory('GetDataList', function($q, $http) {
var promises = [];
var arrDataList = [];
var requests = [{
url: 'https://localhost/search',
postData: {
"param": "1"
}
}, {
url: 'https://localhost/locate',
postData: {
"param": "2"
}
}];
angular.forEach(requests, function(req) {
executeRequest(req);
})
function resolveData(data) {
debugger
if (arrDataList.length === 0) {
arrDataList = data.data;
} else {
arrDataList = arrDataList.concat(data.data);
}
}
function executeRequest(req) {
var promise = $http({
url: req.url,
method: 'GET',
data: req.postData
})
.then(resolveData);
promises.push(promise)
}
return {
getAPIData: function() {
debugger
return $q.all(promises).then(function() {
return arrDataList
});
}
}
});
And your controller:
$scope.GetList = function() {
debugger
GetDataList.getAPIData().then(function(item) {
$scope.item = item
});
$scope.$broadcast('scroll.infiniteScrollComplete');
}
What we are doing here is executing each request inside the requests array (using its url and postData) asynchronously and saving the promises inside an array. When getApiData is called, it returns a function that will be called after $q.all(promises), that means it will return the data after all those promises are finished (the promises ask if the arrDataList is empty and concats the new data if it's not).
This way you get to keep your async calls! And inside the controller you receive a promise instead of the data itself.
You should make it to be synchronized as in the below
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope,serviceDemo) {
$scope.name = 'World';
});
app.factory('serviceDemo', function ($http) {
var arrDataList = [];
var postData1 = []; var postData2 =[]
var firstMethod=function(){
$http({
method: 'GET',
url: 'a.json'
})
.then(function (response) {
console.log(response);
postData1=response.data;
arrDataList.push(postData1);
// console.log(postData1);
secondMethod(); //put the second method call here
});
}
var secondMethod=function(){
$http({
method: 'GET',
url: 'b.json'
})
.then(function (response) {
postData2=response.data;
arrDataList.push(postData2);
console.log(arrDataList);
});
}
var getAPIData= function () {
firstMethod();
return arrDataList;
}
return {
getAPIData: getAPIData
};
});
Modification Made:
You need to call the second method inside the success block of your first method. By this way your first method gets executed, when the result is fetched your second method gets executed and then only control will come out of the first method block.
LIVE DEMO

How to get the data for my controller when http request in progress?

I have following controller
1) introCtrl
2) ArticleCtrl
3) articleService (Service)
Now I am sending an http request from introCrtl
.controller('IntroCtrl', function($scope, articleService) {
articleService.getArticles();
});
and AricleCtrl is
.controller('ArticleCtrl', function($scope,$rootScope,articleService) {
$scope.articles = articleService.fetchArticles();
})
and my Service is
.service('articleService', function ($http, $q) {
var articleList = [];
var getArticles = function() {
$http({
url: "muylink,co,",
data: { starLimit: 0, endLimit: 150,created_date: 0 },
method: 'POST',
withCredentials: true,
}).success(function (data, status, headers, config) {
articleList.push(data);
}).error(function (err) {
console.log(err);
})
};
var fetchArticles = function() {
return articleList[0];
}
return {
getArticles: getArticles,
fetchArticles: fetchArticles
};
});
Which is also working fine. Now Problem is that
Sometimes my http request sending respone late and i got nothing in
$scope.articles.
Can we implement watch here. How i need to implement $watch here. I dont want to implement promise. because i want to run http request behind the scene.
Thanks
It would be better if you switch to a state based setup with ui-router that way you can do this :
$stateProvider.state('myState', {
url: 'the/url/you/want',
resolve:{
articleService: 'articleService' // you are dependency injecting it here,
articles: function (articleService) {
return articleService.getArticles.$promise;
}
},
controller: 'IntroCtrl'
})
// then your controller can just inject the articles and they will be resolved before your controller loads so you it will always be fetched prior
.controller('IntroCtrl', function($scope, articles) {
$scope.articles = articles;
});
for more information take a look at this
ui-router info
All to do is set watch on articleList and provide maintaining function.
As you are watching array, it's good to change it to string.
Create function in watch which results array.
$scope.$watch( function() {
return JSON.stringify($scope.articleList);
}, function(newVal,oldVal){
//provide logic here
});
If your service result is asynchron (like http requests) you should return promises from your service.
.controller('ArticleCtrl', function($scope,$rootScope,articleService) {
articleService.fetchArticles().then(function(articles) {
$scope.articles = articles;
});
})
Service
// not sure about your service logic... simplified:
.service('articleService', function ($http, $q) {
var articleListPromise ;
var getArticles = function() {
articleListPromise = $http(/* ...*/);
};
var fetchArticles = function() {
return articleListPromise.then(function(data) {
return data[0];
});
}
return {
getArticles: getArticles,
fetchArticles: fetchArticles
};
});

Factory does not execute $http.get

My factory does not seem to execute my $http.get. Here's my controller:
app.factory("myService", function($http) {
var myService = {
retrieve: function(id, type) {
var retrievedData = {
device: {},
childDevices: [],
error: {}
};
.
.
.
$http.get(url, headers)
.success(function(data, status) {
// some data post-processing
// some logs
})
.error(function(data, status) {
// some data post-processing
// some logs
});
return retrievedData;
};
return myService;
});
The logs within the $http.get do not print.
I read somewhere I need to use promise, but most examples I saw return $http.get directly. I don't want to return $http.get right away as I need to make some modification on the data in the factory rather than in the controller.
Thanks.
in angular js promise is used for returning response which come from backend. in your code retrievedData return before response come from backend. that's why angular use promise. so when response come from backend it execute success block and success block resolve the promise using deferred.resolve(data) . when error occure then error block get execute and it rejected the promise deferred.reject(err) .but when it resolve the promise it return the response data.
Service Code:
app.factory("myService", function ($http,$q) {
var myService = {
retrieve: function (id, type) {
var deferred = $q.defer();
var retrievedData = {
device: {},
childDevices: [],
error: {}
};
$http.get(url, headers).then(function (data) {
// after success this block execute
deferred.resolve(data);
},
function (err) {
//after error this block execute
deferred.reject(err);
});
return deferred.promise;
}
};
return myService;
});
controller code :
//calling retrive function
myService.retrive(id,type).then(fucntion(data){
...
})
.catch(function(){
...
})
Because when you return your retrievedData it hasn't been retrieved yet. That's why you should use promises:
app.factory("myService", function ($http,$q) {
var myService = {
retrieve: function (id, type) {
var deferred = $q.defer();
var retrievedData = {
device: {},
childDevices: [],
error: {}
};
$http.get(url, headers).then(function (data) {
// success do your success things here and return data
deferred.resolve(data);
},
function (err) {
deferred.reject(err);
});
return deferred.promise;
}
};
return myService;
});
// usage
myService.retrive(id,type).then(function(data){
// data retrived
})

After I call a service my view does not get updated in AngularJS

I have the following service:
angular.module('adminApp')
.factory('subjectService', function ($http) {
return {
get: function (testAccountId) {
return $http({
method: 'GET',
url: '/api/Subjects/GetSelect',
params: { testAccountId: testAccountId }
});
}
}
});
The following code works when I call http directly but now when I use the service:
$scope.$watch('selectedTestAccount', function () {
if ($scope.selectedTestAccount != null) {
$scope.myData = null;
$http({
method: 'GET',
url: '/api/Subjects/GetSelect',
params: { testAccountId: $scope.selectedTestAccount }
}).success(function (result) {
$scope.subjects = result;
$scope.myData = null;
});
//subjectService.get($scope.selectedTestAccount)
// .then(function (result) {
// $scope.subjects = result;
// $scope.myData = null;
// alert($scope.subjects);
// }, function (result) {
// alert("Error: No data returned");
// });
}
});
Related to this question. Is this the correct way to call the service. I saw another suggestion that looked like the following and used promises. Should I be doing this:
services.factory('MultiRecipeLoader', ['Recipe', '$q',
function(Recipe, $q) {
return function() {
var delay = $q.defer();
Recipe.query(function(recipes) {
delay.resolve(recipes);
}, function() {
delay.reject('Unable to fetch recipes');
});
return delay.promise;
};
}]);
I tried to reproduce your exemple in a plunker. Let me know if it is what you are look for:
http://plnkr.co/edit/6s5utccjgHTnrrokM1u8?p=preview
In this demo, there is a dropdown that changes the value of the account variable that is $watched in the controller. If the account value changes, it calls the SubjectsServices and updates the unordered list with the names of the subjects. As an addition, there is also a dropdown filled with the same values.
If the only way to change the value is through the dropdown, maybe you can only use the ng-change directive on the select to call an update function that will do the same work.
$scope.update = function() {
SubjectService.get($scope.account).then(function(result) {
$scope.subjects = result.data;
}, function(result) {
// error handling...
});
};
<select ng-change="update()"></select>
The object received in parameter from the method then on an $http promise has a data property containing the requested data.
$http.get(...).then(function(result) {
var subjects = result.data;
});

Resources