In my angular app I have multiple of $modal
instances which are created like:
var modalInstance = $modal.open({
templateUrl: APP_CONFIG.TPL_PATH + '/path/template.html',
controller: 'TemplateController'//...
});
The problem is that after viewing these modals they are cached, and if I change them, I'm forced to clear the browsers cache. Not a problem on dev machine, but an issue, when I will provide this app to potential users.
I've found these as "solutions" so far:
// first one
$rootScope.$on('$stateChangeStart', function(event, next, current) {
$templateCache.remove(current.templateUrl);
}); // doesn't work because $modal doesn't change state
// second one
$rootScope.$on('$viewContentLoaded', function() {
$templateCache.removeAll();
}); // mess Bootstrap UI which adds default partials directly to the $templateCache
// third one
$modal.open({
templateUrl: '/app/ponents/your-modal.html?bust=' + Math.random().toString(36).slice(2),
controller: 'YourModalController'
}); // ugly and inefficient - I have to change multiple code blocks for every modal
Are there any sufficient solutions? Thank you in advance.
EDIT
An extra advice I got is changing template data and putting it into .js files (i.e <p>Data</p>
to <p>{{data}}</p>
and $scope.data = 'Data'
in .js). Two problems I see here. How can I be sure that the .js file isn't cached by browser? How can I add extra changes to template structure (extra variables), if it's cached (i.e to <p>{{data}}</p><img src='{{imageUrl}}>'
)?
In my angular app I have multiple of $modal
instances which are created like:
var modalInstance = $modal.open({
templateUrl: APP_CONFIG.TPL_PATH + '/path/template.html',
controller: 'TemplateController'//...
});
The problem is that after viewing these modals they are cached, and if I change them, I'm forced to clear the browsers cache. Not a problem on dev machine, but an issue, when I will provide this app to potential users.
I've found these as "solutions" so far:
// first one
$rootScope.$on('$stateChangeStart', function(event, next, current) {
$templateCache.remove(current.templateUrl);
}); // doesn't work because $modal doesn't change state
// second one
$rootScope.$on('$viewContentLoaded', function() {
$templateCache.removeAll();
}); // mess Bootstrap UI which adds default partials directly to the $templateCache
// third one
$modal.open({
templateUrl: '/app/ponents/your-modal.html?bust=' + Math.random().toString(36).slice(2),
controller: 'YourModalController'
}); // ugly and inefficient - I have to change multiple code blocks for every modal
Are there any sufficient solutions? Thank you in advance.
EDIT
An extra advice I got is changing template data and putting it into .js files (i.e <p>Data</p>
to <p>{{data}}</p>
and $scope.data = 'Data'
in .js). Two problems I see here. How can I be sure that the .js file isn't cached by browser? How can I add extra changes to template structure (extra variables), if it's cached (i.e to <p>{{data}}</p><img src='{{imageUrl}}>'
)?
-
Are you dynamically creating the
template.html
file? – Malkus Commented Dec 18, 2015 at 12:02 -
@Malkus Depends on what you mean. I have stored htmls, but use angular to bind to data and display inputs (for example) with data from server (through
$http.post
). In general modals provide access to CRUD operations. – Georgy Commented Dec 18, 2015 at 12:09 - Unfortunately, it is unclear what you are asking. Take a look at how you are structuring your files and what you are trying to acplish and find a more angular way to solve your problem. – Malkus Commented Dec 18, 2015 at 16:25
4 Answers
Reset to default 4Well, when we speak about 'sufficient' it's the matter of taste and particular problem, but I did find this answer to be quite satisfying:
You can't delete browser's cache directly with JavaScript. This is due to security demand. And it's a bit wrong to do this - lots of smart developers know better what to store and what to delete. But there is a simple trick: using of ?keyword=hash
. Even if the pages you see would be similar, if there are different hashes for them, then browser will store two versions of the pages. Adding ?keyword=hash
in every $model.open()
is annoying and unprofessional (DRY, KISS). Let's use angular interceptors
then.
yourApp.factory('HttpInterceptor', function($templateCache, APP_CONFIG) {
return {
'request': function(request) {
if (request.method === 'GET' && $templateCache.get(request.url) === undefined) {
request.url += '?ver=' + APP_CONFIG.VERSION;
}
return request;
}
};
});
Put it into $httpProvider.interceptors
:
$httpProvider.interceptors.push('HttpInterceptor');
Now you can specify version number (take it from your repo, for instance, or include timestamps). The version is changed - browser loads the new version of your templates. The if $templateCache.get(request.url) === undefined
condition is used for filtering requests for precached (automatically injected maybe) content.
Interceptors idea is taken from here: https://stackoverflow./a/25060769/4753661 .
A short summary about your options provided
The first and second options:
// first one
$rootScope.$on('$stateChangeStart', function(event, next, current) {
$templateCache.remove(current.templateUrl);
}); // doesn't work because $modal doesn't change state
// second one
$rootScope.$on('$viewContentLoaded', function() {
$templateCache.removeAll();
}); // mess Bootstrap UI which adds default partials directly to the $templateCache
You defenitly do not want to be arbitrarily clearing items from $templateCache
which seems like what your first two options where doing. Angular would then have to reAdd views to the templateCache over and over again.
The third option:
$modal.open({
templateUrl: '/app/ponents/your-modal.html?bust=' + Math.random().toString(36).slice(2),
controller: 'YourModalController'
}); // ugly and inefficient - I have to change multiple code blocks for every modal
This would actually create a memory leak because you would now have an infinite number of templates being added to the $templateCache.
Better Solutions
My Remended Answer
I would remend renaming your template.html
file to have unique identifiable names.
i.e. modalTemplate_alertModal.html, modalTemplate_newEmployeeModal.html...
Then you get to actually leverage the benefits of the $templateCache
and improve performance.
If you absolutely cannot rename the template.html
files.
In this case you can clear the specific template from the templateCache before you open the modal.
//Get TemplateURL
var TemplateURL = APP_CONFIG.TPL_PATH + '/path/template.html';
//Remove Cached ModalTemplate
$templateCache.remove(TemplateURL);
//Open Modal
var modalInstance = $modal.open({
templateUrl: TemplateURL,
controller: 'TemplateController'//...
});
I can have a static header (i.e.
<h2>Create new entry</h2>
). And then to change it (_<h2>Create new user entry</h2>
). If I had previously viewed the modal, I wouldn't get the updated header without clearing cache.
Based on this statement what you really want to be doing is using the controller
and $scope
to update these values.
<h2>{{modalHeader}}</h2>
Then wherever you are defining what the header needs to be update he value
$scope.modalHeader = "Create new user entry";
Keep in mind angularjs piles and manages the DOM
the only way to properly change DOM
values is using directives
.
add the following section to your webconfig. You will need to clear your current browser cache manually, but going foward a page reload will work,
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Cache-Control" value="no-cache, no-store, must-revalidate" />
<add name="Pragma" value="no-cache" />
<add name="Expires" value="0" />
</customHeaders>
</httpProtocol>
</system.webServer>