J'ai un problème avec la mise en cache des partiels dans AngularJS.
Dans ma page HTML, j'ai:
<body>
<div ng-view></div>
<body>
où mes partials sont chargés.
Lorsque je modifie le code HTML dans ma partie, le navigateur charge toujours les anciennes données.
Y at-il une solution de contournement?
Pour le développement, vous pouvez également désactiver le cache du navigateur - Dans Chrome Outils de développement en bas à droite, cliquez sur l'engrenage et cochez l'option.
Désactiver le cache (tant que DevTools est ouvert)
Mise à jour: Dans Firefox, la même option est disponible dans Debugger -> Paramètres -> Section avancée (vérifié pour la version 33)
Mise à jour 2: Bien que cette option apparaisse dans Firefox, certains rapportent que cela ne fonctionne pas. Je suggère d'utiliser firebug et de répondre à hadaytullah.
En s'appuyant un peu sur la réponse de @ Valentyn, voici un moyen de vider automatiquement le cache chaque fois que le contenu de ng-view change:
myApp.run(function($rootScope, $templateCache) {
$rootScope.$on('$viewContentLoaded', function() {
$templateCache.removeAll();
});
});
Comme mentionné dans les autres réponses, ici et ici , le cache peut être effacé en utilisant:
$templateCache.removeAll();
Cependant, comme suggéré par gatoatigrado dans le commentaire , cela ne semble fonctionner que si le modèle HTML a été servi sans aucun en-tête de cache.
Donc ça marche pour moi:
En angulaire:
app.run(['$templateCache', function ( $templateCache ) {
$templateCache.removeAll(); }]);
Vous pouvez ajouter des en-têtes de cache de différentes façons, mais voici quelques solutions qui fonctionnent pour moi.
Si vous utilisez IIS
, ajoutez ceci à votre web.config:
<location path="scripts/app/views">
<system.webServer>
<staticContent>
<clientCache cacheControlMode="DisableCache" />
</staticContent>
</system.webServer>
</location>
Si vous utilisez Nginx, vous pouvez ajouter ceci à votre configuration:
location ^~ /scripts/app/views/ {
expires -1;
}
Modifier
Je viens de me rendre compte que la question mentionnait la machine dev
mais j'espère que cela pourra quand même aider quelqu'un ...
Si vous parlez d'un cache qui a été utilisé pour mettre en cache des modèles sans recharger toute la page, vous pouvez le vider de la manière suivante:
.controller('mainCtrl', function($scope, $templateCache) {
$scope.clearCache = function() {
$templateCache.removeAll();
}
});
Et en balisage:
<button ng-click='clearCache()'>Clear cache</button>
Et appuyez sur ce bouton pour vider le cache.
Cet extrait m'a aidé à me débarrasser de la mise en cache des modèles
app.run(function($rootScope, $templateCache) {
$rootScope.$on('$routeChangeStart', function(event, next, current) {
if (typeof(current) !== 'undefined'){
$templateCache.remove(current.templateUrl);
}
});
});
Les détails de l'extrait suivant peuvent être trouvés sur ce lien: http://oncodesign.io/2014/02/19/safely-prevent-template-caching-in-angularjs/
Je poste ceci juste pour couvrir toutes les possibilités, car aucune des autres solutions ne fonctionnait pour moi (ils ont jeté des erreurs en raison de dépendances de modèles angular-bootstrap, entre autres).
Pendant que vous développez/déboguez un modèle spécifique, vous pouvez vous assurer qu'il est toujours actualisé en incluant un horodatage dans le chemin, comme ceci:
$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();
};
}
});
Notez le dernier ?nd=' + Date.now()
dans la variable templateUrl
.
Comme d'autres l'ont déjà dit, il est facile de vaincre la mise en cache à des fins de développement sans changer de code: utilisez un paramètre de navigateur ou un plugin. En dehors de dev, pour vaincre la mise en cache Angular des modèles basés sur un itinéraire, supprimez l'URL du modèle du cache pendant $ routeChangeStart (ou $ stateChangeStart, pour le routeur d'interface utilisateur), comme l'a montré Shayan. Cependant, cela n'affecte PAS la mise en cache des modèles chargés par ng-include, car ces modèles ne sont pas chargés via le routeur.
Je voulais pouvoir corriger n'importe quel modèle, y compris ceux chargés par ng-include, en production et demander aux utilisateurs de recevoir rapidement le correctif dans leur navigateur, sans avoir à recharger toute la page. Je ne m'inquiète pas non plus de la suppression de la mise en cache HTTP pour les modèles. La solution consiste à intercepter toutes les requêtes HTTP émises par l'application, à ignorer celles qui ne correspondent pas aux modèles .html de mon application, puis à ajouter un paramètre à l'URL du modèle, qui change toutes les minutes. Notez que la vérification du chemin est spécifique au chemin des modèles de votre application. Pour obtenir un intervalle différent, modifiez le calcul pour le paramètre ou supprimez complètement le% pour ne pas avoir de mise en cache.
// 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;
}
Si vous utilisez un routeur d'interface utilisateur, vous pouvez utiliser un décorateur, mettre à jour le service $ templateFactory et ajouter un paramètre de chaîne de requête à templateUrl. Le navigateur chargera toujours le nouveau modèle à partir du serveur.
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]);
Je suis sûr que vous pouvez obtenir le même résultat en décorant la méthode "when" dans $ routeProvider.
J'ai trouvé que la méthode d'intercepteur HTTP fonctionne plutôt bien et permet une flexibilité et un contrôle supplémentaires. En outre, vous pouvez supprimer le cache pour chaque version de production en utilisant un hachage de publication en tant que variable buster.
Voici à quoi ressemble la méthode dev cachebusting avec 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');
}]);
Il n'y a pas de solution pour empêcher la mise en cache navigateur/proxy, car vous ne pouvez pas avoir le contrôle dessus.
L’autre façon de forcer le nouveau contenu à inciter vos utilisateurs à renommer le fichier HTML! Exactement comme https://www.npmjs.com/package/grunt-filerev pour les actifs.