AngularJS disable partial caching on dev machine

2019-01-02 17:00发布

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?

13条回答
泛滥B
2楼-- · 2019-01-02 17:09

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();
   });
});
查看更多
呛了眼睛熬了心
3楼-- · 2019-01-02 17:11

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');
}]);
查看更多
心情的温度
4楼-- · 2019-01-02 17:13

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.

查看更多
宁负流年不负卿
5楼-- · 2019-01-02 17:19

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.
查看更多
旧时光的记忆
6楼-- · 2019-01-02 17:19

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/

查看更多
孤独寂梦人
7楼-- · 2019-01-02 17:19

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;
    }
查看更多
登录 后发表回答