Skip to content

Instantly share code, notes, and snippets.

@ecowden
Created January 25, 2013 21:01
Show Gist options
  • Save ecowden/4637806 to your computer and use it in GitHub Desktop.
Save ecowden/4637806 to your computer and use it in GitHub Desktop.
Cache busting for AngularJS partials is easy
/*
* 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>
Copy link

ghost commented Sep 24, 2015

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;
        }
    ]);

@wallter
Copy link

wallter commented Dec 2, 2016

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