Created
January 25, 2013 21:01
-
-
Save ecowden/4637806 to your computer and use it in GitHub Desktop.
Cache busting for AngularJS partials is easy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Decide on your cache-busting strategy. In this example, we use the current timestamp, which will | |
* force a change every time the app is visited, but not every time the partial is loaded within a | |
* visit. Even better would be to use a hash of the file's contents to ensure that the file is always | |
* reloaded when the file changes and never reloaded when it isn't. | |
*/ | |
var cacheBustSuffix = Date.now(); | |
// Optionally, expose the cache busting value as a constant so other parts of your app can use it. | |
ngModule.constant("cacheBustSuffix", cacheBustSuffix); | |
// Configure routing | |
ngModule.config(['$routeProvider', function ($routeProvider) { | |
$routeProvider.when('/', { | |
//Append our cache busting value as a query parameter when we specify our templates | |
templateUrl: 'partials/dashboard.html?cache-bust=' + cacheBustSuffix, | |
controller: "DashboardCtrl" | |
}); | |
... | |
$routeProvider.otherwise({redirectTo: '/'}); | |
}]); | |
/* | |
* What if we include a partial within another and it's not referenced directly as a route? | |
* This is one possible approach, though you may want to organize things differently. | |
*/ | |
ngModule.controller("EnterTimesheetCtrl", [ | |
"$scope", "cacheBustSuffix", // we're using the constant declared above | |
function EnterTimesheetCtrl($scope, cacheBustSuffix) { | |
$scope.editableTemplateUrl = "partials/timesheet/editableTimesheet.html?cache-bust=" + cacheBustSuffix; | |
} | |
<div ng-include src="editableTemplateUrl"></div> |
A far superior method to all this complexity, I've found, is a simple directive applied to the element with the ng-include.
ng.directive('ng-include-no-cache', [
'$templateCache',
function($templateCache) {
var directive = {
restrict: 'A',
scope: false,
link: function(scope, element, attributes) {
scope.$parent.$watch(attributes.ngInclude, function(newValue, oldValue){
$templateCache.remove(oldValue);
});
}
};
return directive;
}
]);
Finally got sick and tired of this problem and came up with a different solution — that seems simpler and doesn't require any extensive configuration.
var __version_number = 6.0; // cacheBustSuffix = Date.now('U'); // 'U' -> linux/unix epoch date int
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(function () {
return {
'request': function (config) {
// !!config.cached represents if the request is resolved using
// the angular-templatecache
if (!config.cached) {
config.url += ( (config.url.indexOf('?') > -1) ? '&' : '?' )
+ config.paramSerializer({v: __version_number});
} else if (config.url.indexOf('no-cache') > -1) {
// if the cached URL contains 'no-cache' then remove it from the cache
config.cache.remove(config.url);
config.cached = false; // unknown consequences
// Warning: if you remove the value form the cache, and the asset is not
// accessable at the given URL, you will get a 404 error.
}
return config;
}
}
});
}]);
This will result in all of your app's URL's getting the suffix of '[?|&]v={{date}}'
and if the URL being resolved is in the $templateCache
&& the URL contains 'no-cache'
it will be forced to resolve every time.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I'm assuming @airtonix has this figured out, but for anyone else who ends up here.
Change line 33 to something like:
$scope.editableTemplateUrl = "partials/timesheet/editableTimesheet."+ cacheBustSuffix +".html";
and your server config will need to support the wildcards in the filename
My nginx config has something like: