angularjs not caching resource data . ( even after using cacheFactory ) - angularjs

I am trying to cache the response with angularjs but its not happening .
code #1
var app = angular.module("jsonService", ["ngResource"]);
app.factory("JsonFactory", function($resource,$cacheFactory) {
var cache = $cacheFactory('JsonFactory');
var url = "myurl?domain=:tabUrl";
var data = cache.get(url);
if (data==undefined) {
var retObj = $resource(url, {}, {
list: {
method: "GET",
cache: true
}
});
data = retObj;
cache.put(url, data);
};
return cache.get(url);
});
code #2
var app = angular.module("jsonService", ["ngResource"]);
app.factory("JsonFactory", function($resource) {
var url = "myurl?domain=:tabUrl";
console.log(url);
var retObj = $resource(url, {}, {
list: {
method: "GET",
cache: true
}
});
return retObj;
});
after both the code i wrote . when looking in to dev tools there always goes a XHR request in Network tab.
obviously : date does not changes . ( that's the whole point of caching )

After reading some of your responses, I think that what you are asking, is why does the network tab show a 200 response from your server, while using angular caching.
There are two caches. The first cache is angular's cache. If you see an xhr request in the network tab at all, then that means angular has decided that the url does not exist in its cache, and has asked the browser for a copy of the resource. Furthermore, the browser has looked in it's own cache, and decided that the file in its cache does not exist, or is too old.
Angular's cache is not an offline cache. Every time you refresh the browser page, angular's caching mechanism is reset to empty.
Once you see a request in the network tab, angular has no say in the server response at all. If you're looking for a 304 response from the server, and the server is not providing one, then the problem exists within the server and browser communication, not the client javascript framework.
A 304 response means that the browser has found an old file in its cache and would like the server to validate it. The browser has provided a date, or an etag, and the server has validated the information provided as still valid.
A 200 response means that either the client did not provide any information for the server to validate, or that the information provided has failed validation.
Also, if you use the refresh button in the browser, the browser will send information to the server that is guaranteed to fail (max-age=0), so you will always get a 200 response on a page refresh.

According to the documentation for the version of angular that you are using, ngResource does not support caching yet.
http://code.angularjs.org/1.0.8/docs/api/ngResource.$resource
If you are unable to upgrade your angular version, you may have luck configuring the http service manually before you use $resource.
I'm not exactly sure of syntax, but something like this:
yourModule.run(function($http)
{
$http.cache=true;
});

$cacheFactory can help you cache the response. Try to implement the "JsonFactory" this way:
app.factory("JsonFactory",function($resource,$cacheFactory){
$cacheFactory("JsonFactory");
var url="myurl?domain=:tabUrl";
return{
getResponse:function(tabUrl){
var retObj=$resource(url,{},{list:{method:"GET",cache:true}});
var response=cache.get(tabUrl);
//if response is not cached
if(!response){
//send GET request to fetch response
response=retObj.list({tabUrl:tabUrl});
//add response to cache
cache.put(tabUrl,response);
}
return cache.get(tabUrl);
}
};
});
And use this service in controller:
app.controller("myCtrl",function($scope,$location,JsonFactory){
$scope.clickCount=0;
$scope.jsonpTest = function(){
$scope.result = JsonFactory.getResponse("myTab");
$scope.clickCount++;
}
});
HTML:
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular-resource.js"></script>
<script src="js/ngResource.js"></script>
<body ng-app="app">
<div ng-controller="myCtrl">
<div>Clicked: {{clickCount}}</div>
<div>Response: {{result}}</div>
<input type="button" ng-click="jsonpTest()" value="JSONP"/>
</div>
</body>
Screenshot:
[EDIT] for html5 localStorage solution
JSBin Demo
.factory("JsonFactory",function($resource){
var url="ur/URL/:tabUrl";
var liveTime=60*1000; //1 min
var response = "";
return{
getResponse:function(tabUrl){
var retObj=$resource(url,{},{list:{method:"GET",cache:true}});
if(('localStorage' in window) && window.localStorage !== null){
//no cached data
if(!localStorage[tabUrl] || new Date().getTime()>localStorage[tabUrl+"_expires"]) {
console.log("no cache");
//send GET request to fetch response
response=retObj.list({tabUrl:tabUrl});
//add response to cache
localStorage[tabUrl] = response;
localStorage[tabUrl+"_expires"] = new Date().getTime()+liveTime;
}
//console.log(localStorage.tabUrl.expires+"..."+new Date().getTime());
return localStorage[tabUrl];
}
//client doesn't support local cache, send request to fetch response
response=retObj.list({tabUrl:tabUrl});
return response;
}
};
});
Hope this is helpful for you.

Related

Unable to get a JSON response from my express router using node-Fetch module

So I'm making a post request to my Express search router where I'm using the node-fetch module to call a remote api:
var fetch = require('node-fetch');
router.route('/search')
//Performs Job Search
.post(function(req, res){
var area = req.body.area;
fetch('https://api.indeed.com/ads/apisearch?publisher=*********&l=' + area)
.then(function(res) {
return res.json();
}).then(function(json) {
console.log(json);
});
})
I'm using angular 1 on the client side to call the router and parse the returned json:
$scope.search = function(){
$http.post('/api/search', $scope.newSearch).success(function(data){
if(data.state == 'success'){
//perform JSON parsing here
}
else{
$scope.error_message = data.message;
}
});
}
I'm just starting out with the MEAN stack and only have a vague idea of how promises work. So my issue is that my angular search function is not getting the JSON string I want to return from my remote API call. But rather the data parameter is getting set to my page html. Eventually the breakpoints I've set in the .then() clauses are hit and my json is returned. So my question is how can I use Anguular to get the JSON values when they are finally returned????
Can you try something like this?
router.route('/search')
//Performs Job Search
.post(function(req, res){
var area = req.body.area;
fetch('https://api.indeed.com/ads/apisearch?publisher=*********&l=' + area)
.then(function(result) {
res.json(result);
//or possibly res.send(result), depending on what indeed responds with
})
})
Turns out I had forgotten that I had middleware in place where if the user was not authenticated when performing the search they were redirected to the login page. So I was getting a bunch of html returned for this login page, rather then my json. What still confuses me is why my breakpoints in search function were ever hit if I was being redirected before ever reaching this function.

Passing External API to Angularjs

I'm working with an external API from Shipstation. I can do a GET request to pull the information in just fine into Nodejs, but I can't figure out how I can transfer that data client-side to manipulate within Angular? I've been struggling with this for a few days now and all my googling searching isn't helping out.
server.js
var express = require('express');
var request = require('request');
var app = express();
app.use(express.static('public'));
var Orders = require('./controllers/ordersController');
app.use('/orders', Orders);
app.listen(3000, function() {
console.log('I am live on port 3000');
});
ordersController.js
var request = require('request');
module.export = request({
method: 'GET',
url: 'https://ssapi.shipstation.com/orders/listbytag?orderStatus=awaiting_shipment&tagId=32099&page=1&pageSize=100',
headers: {
'Authorization': 'xxxxxxxxxxx'
}}, function (error, response, body) {
console.log('Status:', response.statusCode);
console.log('Headers:', JSON.stringify(response.headers));
console.log('Response:', body);
});
I figured the best way was to put the GET request in its own "orders" module, export it, and then have angular access that route in an http request (/orders). Sounds good in theory, right?
I appreciate the help in advance! Thanks guys!
I'm assuming that the ShipStation API provides JSON which is easily consumable by Angular.
You can load the JSON into your Angular app like this:
$http.get('/orders:3000', function(data) {
$scope.Orders = data;
console.log($scope.Orders);
});
Add this to your controller, then check the browser's developer console to see the output. From there, you can manipulate the JSON object however you need and display the information in your HTML view.

$http.get success method not called

I am new to AngularJS & NodeJS. I am trying to get a API response from NodeJS and display it in angular. I am using $http to make API call. Below is my nodeJS code.
var express = require('express');
var app = express();
app.get('/employees',function(req,res)
{
console.log("Test Output :");
res.status(200).send('Hello User');
});
app.listen(8080);
Below is my angular code
var myapp = angular.module('myapp',[]).controller('myappController', ['$scope','$http',function ($scope,$http){
$http.get('http://127.0.0.1:8080/employees')
.then(function(response)
{
window.alert("Success");
$scope.emdata=response.data;
},function(errorresponse)
{
window.alert("Error");
$scope.emdata=errorresponse.status;
});
}]);
I am using expression {{emdata}} in HTML page. When I open the HTML page I can see the console output "Test Output " in NodeJS terminal which means the API is getting called but I dont see "Hello User" in HTML page. It looks like the success function in $http.get is not getting called and only the error function is getting called. So I see an alert window with "Error" whenever I open the HTML page and response status as -1 in the place of {{emdata}}.
When I tried making the API call using Postman I get correct response with status 200. So I am wondering what is wrong?
Check headers, i.e. what format is accepted by $http request and the format of the response (JSON, plain text, etc).
Fix value in
$httpProvider.defaults.headers.common
or set needed one in
$httpProvider.defaults.headers.get = { ... };
or just use
var requestParams = {
method: 'GET',
url: '...',
headers: {
...
}
};
$http(requestParams).then(...);
Take a look at Setting HTTP Headers in official manual for more details.

API-key header is not sent (or recognized). Angularjs

I'm trying to access an API with AngularJS but I get the following error:
XMLHttpRequest cannot load http://www.football-data.org/alpha/soccerseasons/398/leagueTable?callback=JSON_CALLBACK. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://purepremier.com' is therefore not allowed access.
This is my code for the service:
angular.module('PremierLeagueApp.services', []).
factory('footballdataAPIservice', function($http) {
var footballdataAPI = {};
footballdataAPI.getTeams = function() {
$http.defaults.headers.common['Auth-Token'] = 'token';
return $http.get('http://www.football-data.org/alpha/soccerseasons/398/leagueTable?callback=JSON_CALLBACK');
};
return footballdataAPI;
});
I use an authentication token (api key) to access the api, but according the API owner this API key header is not sent or recognized. Do you have any idea how I can adapt the code to make this work? thanks!
You should hide that API key before posting on a public site such as this. I would advise you regenerate your key (if possible) just in case - better safe than sorry.
Assuming your site url is 'http://purepremier.com' from the error message, the API should add a 'Access-Control-Allow-Origin' header with your site URL to allow you access. Have a look here for more information.
This is not directly related to your problem, but I notice you are setting $http defaults every time getTeams() is called. You should either set this outside of the actual function call (preferably in a run block), or just send the GET request with that header specifically applied. As the API key is specific (I assume) to that call, you may not want to be sending it to anyone and everyone, every time you make a HTTP request.
Change your factory code like this:
factory('footballdataAPIservice', function($http) {
return {
getTeams: function(){
return $http({
url:'http://www.football-data.org/alpha/soccerseasons/398/leagueTable',
headers: { 'X-Auth-Token': 'your_token' },
method: 'GET'
}).success(function(data){
return data;
});
}
}
});
Inject factory in your controller and retreive the data:
.controller('someController',function(footballdataAPIservice,$scope){
footballdataAPIservice.getTeams().then(function(data){
$scope.teams=data;
console.log($scope.teams)
});
});
Here is the working plunker
You change the Auth-Token To Authorization
$http.defaults.headers.common['Authorization'] = 'token';
Because token is send via headers using Authorization
try jsonp
angular.module('PremierLeagueApp.services', []).
factory('footballdataAPIservice', function($http) {
var footballdataAPI = {};
footballdataAPI.getTeams = function() {
$http.defaults.headers.common['Auth-Token'] = 'token';
return $http.jsonp('http://www.football-data.org/alpha/soccerseasons/398/leagueTable?callback=JSON_CALLBACK');
};
return footballdataAPI;
});

Preserving scope across routed views

I have a SPA with a list of Clients displayed on the landing page. Each client has an edit button, which if clicked should take me to an Edit view for that selected Client.
I'm not sure how to go about this- all the routes I've seen so far will just take my client id in the $routeParams, and then most examples will then pull the Client from a factory by that Id.
But I already HAVE my Client... seems a waste to hit my web api site again when I already have it. Is it possible to route to the new view and maintain the selected Client in the $scope?
Edit:
This is what I did- I don't know if it's better or worse than Clarks response... I just made the following angular service:
app.service('clientService', function () {
var client = null;
this.getClient = function () {
return client;
};
this.setClient = function (selectedClient) {
client = selectedClient;
};
});
And then for any controller that needs that data:
$scope.client = clientService.getClient();
This seemed to work fine... but would love to hear how this is good or bad.
Depends on what level of caching you want.
You could depend on browser caching, in which case proper HTTP headers will suffice.
You could depend on cache provided by $http in angular, in which case making sure the parameters you send up are the same would be sufficient.
You could also create your own model caching along the lines of :
module.factory('ClientModel', function($http, $cacheFactory, $q){
var cache = $cacheFactory('ClientModel');
return {
get : function(id){
var data = cache.get(id);
if(data){
//Using $q.when to keep the method asynchronous even if data is coming from cache
return $q.when(data);
} else {
//Your service logic here:
var promise = $http.get('/foo/bar', params).then(function(response){
//Your model logic here
var data = response;
cache.put(id, data);
return response;
}, function(response){
cache.remove(id);
return response;
});
//Store the promise so multiple concurrent calls will only make 1 http request
cache.put(id, promise);
return promise;
}
},
clear : function(id){
if(angular.isDefined(id)){
cache.remove(id);
} else {
cache.removeAll();
}
}
}
});
module.controller('ControllerA', function(ClientModel){
ClientModel.get(1).then(function(){
//Do what you want here
});
});
module.controller('ControllerB', function(ClientModel){
ClientModel.get(1).then(function(){
//Do what you want here
});
});
Which would mean each time you request a client object with the same 'id', you would get the same object back.

Resources