Angular disable cached partials in production

All we need is an easy explanation of the problem, so here it is.

I’m in proccess of development site, but every time i upload a new version to my server the users need to clean there cache to see the changes, what is the solution to this problem?

I try two ways to solve this thing from answers to questions here:

The first way:

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

But this way have a problem with things like ui.bootstrap and its throw error.

The second way:

$rootScope.$on("$stateChangeStart", function( event, toState, current ) {

    if (typeof(current) !== 'undefined'){
      $templateCache.remove(current.templateUrl);
    }
})

This not throw error, but i dont know if this solution is the right one and if it work, what i need to do?

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

This is a problem with the server configuration, and how it tells the browser to cache the HTML files used as template partials.

Understanding Browser Caching

You are attempting to do $templateCache.remove(..) and $templateCache.removeAll() which is not going to work, because the templates haven’t been loaded yet, or the browser will just reload them using the cached version.

You need to check the network history in the browser to ensure that the server is handling HTML requests correctly. Send the header settings for caching that you expected. For each partial, there should be a 302 (not modified) response. When the HTML file has changed then the server should send the new modified one to the browser.

The other problem is your default cache duration on the server might be too long. This tells the browser how often it should check the server to send new versions of the HTML file. You might want to reduce this duration to 1 hour.

Most web servers are pre-configured to assume a file with the extension .html will never change and is static. So the default settings are to have the browser cache those files for as a long as possible.

You might want to rename those files to something like .ahtml and use that as your partial file names. There shouldn’t be any pre-defined configuration to force cashing of those file types.

Understanding $templateCache

This is a very simple cache service in AngularJS. If the URL is not found in memory it is loaded from the server. The next time that partial is needed while the app is running the memory version is used. The usage of this server has nothing to do with server/browser caching.

Templates The Right Way

It’s a best practice to create a single JavaScript file that contains all the partial templates the application will need. This JS file will call the $templateCache service and add those templates. This improves the startup performance of your application, and removes the problem of dealing with server/browser caching.

There are several grunt tasks that can do this.

https://www.npmjs.com/package/grunt-angular-templates

https://github.com/karlgoldstein/grunt-html2js

Combine this will a JavaScript minifier and concat all your JS into a single file, and you’re well on your way.

Method 2

Here is a pretty straight-forward way to do this. Each deployment has a unique hash, which get’s used within an HTTP interceptor to request new partial templates for each production release:

app.factory('cachebustInjector', function(conf) {
    // generated each deploy   
    var buster = 'kaqreFZ3MWcGzfS86iSiud'; 

    var cachebustInjector = {
        request: function(config) {    
            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');
}]);

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

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 Reply