I have used cache:false in my state to avoid templates(html view) caching like below.
.state('index.project_setup', {
url: '/:customerTag/project-setup',
templateUrl: 'app/views/common/customer/projects/setup_projects_wizard.html',
data: { pageTitle: 'Project Setup' },
cache: false
})
After applying changes in to html file, sometimes i need to hard refresh the page instead of just reload. So is it something i am missing or is there any way to accomplish this thing?
There is a difference between Angular template caching and your browser caching.
When Angular loads a template for the first time, it will fire an AJAX request for that template, and then store the HTMLin a service called $templateCache, so if the exact same template is required again, it will skip the AJAX call and will use the HTML stored in $templateCache.
Once you refreshed your page, the $templateCache service is initialized (because all the JS is initialized) and all the cached HTMLs are gone, so again when Angular will require an HTML file for a template, it will fire AJAX call the first time, store it in the $templateCache and then will use the cached HTML from here on out.
Your browser on the other hand, does not "initialize" his cache on every refresh, so if you will request a file that was cached before, the browser will skip the HTTP call and will use his cached version if one is available.
So lets say we need template named x.html, what will happen is the following pseudo code:
if (x.html exists in $templateCache)
return x.html from $templateCache
else
AngularJS perform HTTP GET for x.html
if (browser has x.html cached version)
return x.html from browser cache and don't fire HTTP request
else
fire HTTP request for x.html and return the result
That is way you must "hard reload" your templates every once in a while.
My solution for development, is attaching a changing query string to the template URL, for example:
.state('index.project_setup', {
url: '/:customerTag/project-setup',
templateUrl: 'app/views/common/customer/projects/setup_projects_wizard.html?v=' + Date.now(),
data: { pageTitle: 'Project Setup' },
cache: false
})
That is a simple trick that causes the browser to always fetch the HTML file because the query string is never the same (well, it will be the same for 1 millisecond :)), so every time the browser will get an HTTP request for that HTML, it will not match previous requests and will not use the cache.
Related
I am making $http get call in my application. A single page has a need where this call is made thrice asynchronously. When I set cache to true for the http call it works fine ie it does make only one request to the server. Requirement is only to cache them for a shorter period. So I need to make for the entire page one request is hit to server and the subsequent ones are cached and also the next request to the page ie page refresh should make should hit server and cache the fresh response.
For that purpose, I would like to understand what is the default values like how long does the response remains in the $cacheFactory and is the cache type private or public.
I am aware of the alternative solution, what I am looking here is to know what is the time that this get call is cached for?
$http(
{
method: 'POST',
url: '/test/api/component/getItem',
data: {
projectPath : projectPath
}
}
).then(unwrap);
Right now, I have a factory which loads a JSON file.
angular.module("app").factory("RolesFactory", ['$http', '$q', function($http, $q) {
var d = $q.defer();
$http.get('events.json').success(function(data) {
d.resolve(data);
});
return d.promise;
}]);
And then I call this factory when I need the contents of events.json with this controller:
App.controller('rolesCtrl', ['$scope', 'RolesFactory', function($scope, RolesFactory) {
RolesFactory.then(function(roleData){
$scope.roles = roleData.roles;
});
}]);
All good, but whenever I need to use this data. Isn't it refetching the contents of events.json? Meaning: is Angular reloading the file over and over again? I was hoping to load the file once and call it by a global variable or something.
When my app loads initially, I want it to load and store the contens of events.json -- and then I'd like my app to be able to use this data whenever/wherever.
Is this possible?
As AngularJS is a stateless framework, you have only a few options here, all of which are some kind of client-side caching:
Use localStorage to store your data. Once the data is fetched, you can just save it to localStorage using localStorage.setItem after Stringifying the JSON. You'll need to re-parse the JSON the next time you use it though, so if this is a giant JSON, this is not the best idea
Use sessionStorage to store your data. This is exactly the same as #1, but you will lose data upon termination of session,i.e. closing your browser.
Trust the JSON to be cached in your browser. This is most likely the case. Static assets are by default cached by most modern browsers. So, the second time your factory requests the JSON, the resource isn't actually fetched from the server. It is merely pulled from the browser's cache.
NOTE: The way to check this is to see what the HTTP status code for your resource is, in Chrome's Developer Tools Network tab. If the status says 304 that means it has been pulled from cache.
I am using Angular's default $http cache in one of my services. When the user navigates from a view to another one (I am using ui-router), the cache invalidates and all of the items will be removed from it. I want to not invalidate the cache in the whole lifetime of my application.
EDIT:
For example, this factory does not return cached result after navigating to another route and it calls the server api to get the result:
cardModule.factory("myFactory", function ($http) {
return {
getAll: function () {
return $http.get("all", { cache: true })
}
}
});
How to prevent default cache from removing items from itself after a route change?
I found the source of the problem. It was my own fault. I had a code somewhere that clears the cache after the state change. There is no problem with default angular $http cache.
I would leave this as a comment but I don't have enough points yet..
Could you try some form of memoisation? In other words, have a model on the scope, then, if the model is undefined, trigger the $http call? Something like:
var ctrl = this;
ctrl.product = undefined; // or null
if (ctrl.product === undefined) { // or null
$http.get(...).then(function(resp) {
ctrl.product = resp.data;
};
};
This way the model gets initialized, and called just once. A possible downside would be that the if statement may make this inefficient.
I have not tested this, just throwing the idea out there. I am also very interested in this problem.
That should not be related to ui-router or $http. Here are a few things you need to confirm:
Is your server (which is serving your resources) is setting the cache header or not
Make sure you are not using Ctrl + F5 to refresh the page
If you are using Chrome browser, make sure a setting Disable cache is unchecked
I am using Angular ui router (https://github.com/angular-ui/ui-router) and coming across an unexpected behavior.
I have a recordView and recordEdit states set up and using sref/$state.transitionTo to switch between them.
When in recordEdit state, update is being done via ajax and upon success, I am programatically chaning the state into recordView.
Problem is that the recordView state does not show the update data and will only show it if I refresh the page.
I tried using the reload option but with no success.
App.saveRecord($scope.formData).then(function (response) {
$state.transitionTo('recordView', $stateParams, {
reload: true
});
}
I also tried using $state.go(...) but getting the same result.
I also tried using the cache = false on the state property but with no success.
.state('recordView', {
url: '/folder/:hash/:recordId',
resolve: {},
cache: false,
templateUrl: function (urlattr) {
//return the url
}
})
I then tried explicitly changing the window.location to the view url but it will still show the previous data.
The only time it will actually work is if I call location.reload(); after changing the state but this is not good for the user experience.
Does anyone know why this is happening? all the posts I've seen about it mention setting the reload to true or the cache to false.
UPDATE
Per the comments I understand that the problem is that I am using ng-init and server side rendering to inject the data from php to angular and when reloading the view, this data is not reloading.
My questions then are:
Can I "inject" the edited data from the recordEdit state into the recordView state after the user edited the data?
Is there a way to simply force a reload of the page and ignore the caching? Basically simulate as if the route was hit for the first time.
Thanks.
Here is an idea.
On your routes file define a parent abstract state and initialize that with the data
.state('parent.state'
{
abstract: true,
data:{
init://server rendered data here
}
}
)
.state('child.state.view',
{
// your route definition here
}
)
.state('child.state.edit',
{
// your route definition here
}
)
then in your controllers inject the $state service in yout view controller use
//assuming the data variable holds the needed data. change that to what ever
$scope.data = $state.current.data.init; //if using $scope
this.state = $state.current.data.init; //if controller As syntax
Remove the ng-init sentence as the data will be initialized on the controller. Then on the Update function in the edit view make sure you update the $state.current.data.init with the new data. This way next time you go there the controller will pick the data from the $state object and get the updated one.
Answer:
$templateCache.remove('http://urlthemplate');
What is a good pattern for updating angular data from a ngResource service that has been cached?
I been trawling posts like this one [1]: How to refresh / invalidate $resource cache in AngularJS, but would be good to hear from angular experts on the right approach for this specific (but pretty general) scenario.
I am looking for a general pattern here. Both in understanding and in implementing angular - I am a novice at it.
I have a pretty standard ngResource service that has a very standard query method, and a custom put method update.
myServices.factory('ThingsService', [
'$resource',
function ($resource) {
return $resource('/api/things/:id', { id: '#id' }, {
query: { method: 'GET', isArray: true, cache: true },
update: {method: 'PUT', cache: true },
});
}]);
I am using it from a controller like this:
$scope.things = ThingsService.query(function (x) {
// must assign these only once data is loaded
$scope.allCount = x.Things.length;
$scope.incomingCount = $filter('filter')(x.Things, { State: 'incoming' }).length;
});
So far so good. The data is returned just fine, and it renders nicely in a dashboard view.
We support in-place-editing and the user can edit the data right there in the dashboard list.
First take a shadow copy of the thing using angular.copy(...) so that we can support buffering of the changes for the user. (just like a dialog box does for a user). Then when they confirm their changes, we call with the shadow copy:
ThingsService.update({ id: currentThing.Id }, { Data: currentThing.Data }, function () {
//TODO: now, if this PUT succeeds,
//I want to update the value of $scope.things array to reflect the changes,
//without going to back to the server for the whole array.
});
This correctly PUTS the changes to the server, which returns an updated thing, but the dashboard view which is bound to the query method is not updated auto-magically. Was kind of hoping angular and the ThingsService and its cache would take care of that for me somehow, you know by updating the cached data. Since the service should know that I just updated one of the items that the service serves up.
So to avoid going all the way back to the server we have told the ThingsService to cache its results, which is a good start. But how are you supposed to update the changed thing in the cached data?
Is there a standard pattern for this kind of update with a ngResource service?
Preferably I wouldn't have to mess with the cache directly. I should not even care that it is cached or how. I just want $scope.things to reflect the posted changes changes.