AngularJS disable partial caching on dev machine

The question:

I have problem with caching partials in AngularJS.

In my HTML page I have:

<body>
 <div ng-view></div>
<body>

where my partials are loaded.

When I change HTML code in my partial, browser still load old data.

Is there any workaround?

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

For Development you can also deactivate the browser cache – In Chrome Dev Tools on the bottom right click on the gear and tick the option

Disable cache (while DevTools is open)

Update: In Firefox there is the same option in Debugger -> Settings -> Advanced Section (checked for Version 33)

Update 2: Although this option appears in Firefox some report it doesn’t work. I suggest using firebug and following hadaytullah answer.

Method 2

Building on @Valentyn’s answer a bit, here’s one way to always automatically clear the cache whenever the ng-view content changes:

myApp.run(function($rootScope, $templateCache) {
   $rootScope.$on('$viewContentLoaded', function() {
      $templateCache.removeAll();
   });
});

Method 3

As mentioned in the other answers, here and here, the cache can be cleared by using:

$templateCache.removeAll();

However as suggested by gatoatigrado in the comment, this only appears to work if the html template was served without any cache headers.

So this works for me:

In angular:

app.run(['$templateCache', function ( $templateCache ) {
    $templateCache.removeAll(); }]);

You may be adding cache headers in a variety of ways but here are a couple of solutions that work for me.

If using IIS, add this to your web.config:

<location path="scripts/app/views">
  <system.webServer>
    <staticContent>
      <clientCache cacheControlMode="DisableCache" />
    </staticContent>
  </system.webServer>
</location>

If using Nginx, you can add this to your config:

location ^~ /scripts/app/views/ {
    expires -1;   
}

Edit

I just realised that the question mentioned dev machine but hopefully this may still help somebody…

Method 4

If you are talking about cache that is been used for caching of templates without reloading whole page, then you can empty it by something like:

.controller('mainCtrl', function($scope, $templateCache) {
  $scope.clearCache = function() { 
    $templateCache.removeAll();
  }
});

And in markup:

<button ng-click='clearCache()'>Clear cache</button>

And press this button to clear cache.

Method 5

Solution For Firefox (33.1.1) using Firebug (22.0.6)

  1. Tools > Web-Tools > Firebug > Open Firebug.
  2. In the Firebug views go to the “Net” view.
  3. A drop down menu symbol will appear next to “Net” (title of the view).
  4. Select “Disable Browser Cache” from the drop down menu.

Method 6

This snippet helped me in getting rid of template caching

app.run(function($rootScope, $templateCache) {
    $rootScope.$on('$routeChangeStart', function(event, next, current) {
        if (typeof(current) !== 'undefined'){
            $templateCache.remove(current.templateUrl);
        }
    });
});

The details of following snippet can be found on this link:
http://oncodesign.io/2014/02/19/safely-prevent-template-caching-in-angularjs/

Method 7

I’m posting this just to cover all possibilities since neither of the other solutions worked for me (they threw errors due angular-bootstrap template dependencies, among others).

While you are developing/debugging a specific template, you can ensure it always refreshes by included a timestamp in the path, like this:

       $modal.open({
          // TODO: Only while dev/debug. Remove later.
          templateUrl: 'core/admin/organizations/modal-selector/modal-selector.html?nd=' + Date.now(),
          controller : function ($scope, $modalInstance) {
            $scope.ok = function () {
              $modalInstance.close();
            };
          }
        });

Note the final ?nd=' + Date.now() in the templateUrl variable.

Method 8

As others have said, defeating caching completely for dev purposes can be done easily without changing code: use a browser setting or a plugin. Outside of dev, to defeat Angular template caching of route-based templates, remove the template URL from the cache during $routeChangeStart (or $stateChangeStart, for UI Router) as Shayan showed. However, that does NOT affect the caching of templates loaded by ng-include, because those templates are not loaded through the router.

I wanted to be able to hotfix any template, including those loaded by ng-include, in production and have users receive the hotfix in their browser quickly, without having to reload the entire page. I’m also not concerned about defeating HTTP caching for templates. The solution is to intercept every HTTP request that the app makes, ignore those that are not for my app’s .html templates, then add a param to the template’s URL that changes every minute. Note that the path-checking is specific to the path of your app’s templates. To get a different interval, change the math for the param, or remove the % completely to get no caching.

// this defeats Angular's $templateCache on a 1-minute interval
// as a side-effect it also defeats HTTP (browser) caching
angular.module('myApp').config(function($httpProvider, ...) {
    $httpProvider.interceptors.push(function() {
        return {
            'request': function(config) {
                config.url = getTimeVersionedUrl(config.url);
                return config;
            }
        };
    });

    function getTimeVersionedUrl(url) {
        // only do for html templates of this app
        // NOTE: the path to test for is app dependent!
        if (!url || url.indexOf('a/app/') < 0 || url.indexOf('.html') < 0) return url;
        // create a URL param that changes every minute
        // and add it intelligently to the template's previous url
        var param = 'v=' + ~~(Date.now() / 60000) % 10000; // 4 unique digits every minute
        if (url.indexOf('?') > 0) {
            if (url.indexOf('v=') > 0) return url.replace(/v=[0-9](4)/, param);
            return url + '&' + param;
        }
        return url + '?' + param;
    }

Method 9

If you are using UI router then you can use a decorator and update $templateFactory service and append a query string parameter to templateUrl, and the browser will always load the new template from the server.

function configureTemplateFactory($provide) {
    // Set a suffix outside the decorator function 
    var cacheBust = Date.now().toString();

    function templateFactoryDecorator($delegate) {
        var fromUrl = angular.bind($delegate, $delegate.fromUrl);
        $delegate.fromUrl = function (url, params) {
            if (url !== null && angular.isDefined(url) && angular.isString(url)) {
                url += (url.indexOf("?") === -1 ? "?" : "&");
                url += "v=" + cacheBust;
            }

            return fromUrl(url, params);
        };

        return $delegate;
    }

    $provide.decorator('$templateFactory', ['$delegate', templateFactoryDecorator]);
}

app.config(['$provide', configureTemplateFactory]);

I am sure you can achieve the same result by decorating the “when” method in $routeProvider.

Method 10

I found that the HTTP interceptor method works pretty nicely, and allows additional flexibility & control. Additionally, you can cache-bust for each production release by using a release hash as the buster variable.

Here is what the dev cachebusting method looks like using Date.

app.factory('cachebustInjector', function(conf) {   
    var cachebustInjector = {
        request: function(config) {    
            // new timestamp will be appended to each new partial .html request to prevent caching in a dev environment               
            var buster = new Date().getTime();

            if (config.url.indexOf('static/angular_templates') > -1) {
                config.url += ['?v=', buster].join('');
            }
            return config;
        }
    };
    return cachebustInjector;
});

app.config(['$httpProvider', function($httpProvider) {
    $httpProvider.interceptors.push('cachebustInjector');
}]);

Method 11

Here is another option in Chrome.

Hit F12 to open developer tools. Then Resources > Cache Storage > Refresh Caches.

enter image description here

I like this option because I don’t have to disable cache as in other answers.

Method 12

There is no solution to prevent browser/proxy caching since you cannot have the control on it.

The other way to force fresh content to your users it to rename the HTML file! Exactly like https://www.npmjs.com/package/grunt-filerev does for assets.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment