Cela a déjà été demandé, et d'après les réponses, cela n'a pas l'air bien. Je voudrais demander avec cet exemple de code en considération ...
Mon application charge l'élément actuel dans le service qui le fournit. Il existe plusieurs contrôleurs qui manipulent les données d'élément sans que l'élément ne soit rechargé.
Mes contrôleurs rechargeront l'élément s'il n'est pas encore défini, sinon, il utilisera l'élément actuellement chargé depuis le service, entre les contrôleurs.
Problème : je voudrais utiliser des chemins différents pour chaque contrôleur sans recharger Item.html.
1) Est-ce possible?
2) Si ce n'est pas possible, y a-t-il une meilleure approche pour avoir un chemin par contrôleur par rapport à ce que j'ai proposé ici?
app.js
var app = angular.module('myModule', []).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/items', {templateUrl: 'partials/items.html', controller: ItemsCtrl}).
when('/items/:itemId/foo', {templateUrl: 'partials/item.html', controller: ItemFooCtrl}).
when('/items/:itemId/bar', {templateUrl: 'partials/item.html', controller: ItemBarCtrl}).
otherwise({redirectTo: '/items'});
}]);
Item.html
<!-- Menu -->
<a id="fooTab" my-active-directive="view.name" href="#/item/{{item.id}}/foo">Foo</a>
<a id="barTab" my-active-directive="view.name" href="#/item/{{item.id}}/bar">Bar</a>
<!-- Content -->
<div class="content" ng-include="" src="view.template"></div>
controller.js
// Helper function to load $scope.item if refresh or directly linked
function itemCtrlInit($scope, $routeParams, MyService) {
$scope.item = MyService.currentItem;
if (!$scope.item) {
MyService.currentItem = MyService.get({itemId: $routeParams.itemId});
$scope.item = MyService.currentItem;
}
}
function itemFooCtrl($scope, $routeParams, MyService) {
$scope.view = {name: 'foo', template: 'partials/itemFoo.html'};
itemCtrlInit($scope, $routeParams, MyService);
}
function itemBarCtrl($scope, $routeParams, MyService) {
$scope.view = {name: 'bar', template: 'partials/itemBar.html'};
itemCtrlInit($scope, $routeParams, MyService);
}
Résolution.
Statut : L'utilisation de la requête de recherche comme recommandé dans la réponse acceptée m'a permis de fournir différentes URL sans recharger le contrôleur principal.
app.js
var app = angular.module('myModule', []).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/items', {templateUrl: 'partials/items.html', controller: ItemsCtrl}).
when('/item/:itemId/', {templateUrl: 'partials/item.html', controller: ItemCtrl, reloadOnSearch: false}).
otherwise({redirectTo: '/items'});
}]);
Item.html
<!-- Menu -->
<dd id="fooTab" item-tab="view.name" ng-click="view = views.foo;"><a href="#/item/{{item.id}}/?view=foo">Foo</a></dd>
<dd id="barTab" item-tab="view.name" ng-click="view = views.bar;"><a href="#/item/{{item.id}}/?view=foo">Bar</a></dd>
<!-- Content -->
<div class="content" ng-include="" src="view.template"></div>
controller.js
function ItemCtrl($scope, $routeParams, Appts) {
$scope.views = {
foo: {name: 'foo', template: 'partials/itemFoo.html'},
bar: {name: 'bar', template: 'partials/itemBar.html'},
}
$scope.view = $scope.views[$routeParams.view];
}
directives.js
app.directive('itemTab', function(){
return function(scope, elem, attrs) {
scope.$watch(attrs.itemTab, function(val) {
if (val+'Tab' == attrs.id) {
elem.addClass('active');
} else {
elem.removeClass('active');
}
});
}
});
Le contenu de mes partiels est enveloppé de ng-controller=...
Réponses:
Si vous n'avez pas besoin d'utiliser des URL comme
#/item/{{item.id}}/foo
et#/item/{{item.id}}/bar
mais#/item/{{item.id}}/?foo
et à la#/item/{{item.id}}/?bar
place, vous pouvez configurer votre route pour/item/{{item.id}}/
avoirreloadOnSearch
défini surfalse
( https://docs.angularjs.org/api/ngRoute/provider/$routeProvider ). Cela indique à AngularJS de ne pas recharger la vue si la partie recherche de l'URL change.la source
ng-controller="view.controller"
à lang-include
directive.<div ng-controller="itemFooCtrl">... your template content...</div>
. EDIT: Ravi de vous voir résolu, ce serait bien si vous mettiez à jour votre question avec comment vous l'avez résolue, peut-être avec un jsFiddle.Si vous devez modifier le chemin, ajoutez-le après votre .config dans votre fichier d'application. Ensuite, vous pouvez faire
$location.path('/sampleurl', false);
pour empêcher le rechargementapp.run(['$route', '$rootScope', '$location', function ($route, $rootScope, $location) { var original = $location.path; $location.path = function (path, reload) { if (reload === false) { var lastRoute = $route.current; var un = $rootScope.$on('$locationChangeSuccess', function () { $route.current = lastRoute; un(); }); } return original.apply($location, [path]); }; }])
Le crédit va à https://www.consolelog.io/angularjs-change-path-without-reloading pour la solution la plus élégante que j'ai trouvée.
la source
$timeout(un, 200);
avant la déclaration de retour car parfois$locationChangeSuccess
ne se déclenchait pas du tout aprèsapply
(et l'itinéraire n'était pas changé quand c'était vraiment nécessaire). Ma solution clarifie les choses après l'invocation du chemin (..., false)pourquoi ne pas simplement mettre le ng-controller un niveau plus haut,
<body ng-controller="ProjectController"> <div ng-view><div>
Et ne placez pas le contrôleur dans l'itinéraire,
.when('/', { templateUrl: "abc.html" })
ça marche pour moi.
la source
Pour ceux qui ont besoin d'un changement de chemin () sans rechargement des contrôleurs - Voici le plugin: https://github.com/anglibs/angular-location-update
Usage:
$location.update_path('/notes/1');
Basé sur https://stackoverflow.com/a/24102139/1751321
PS Cette solution https://stackoverflow.com/a/24102139/1751321 contient un bug après le chemin (, false) appelé - cela interrompra la navigation du navigateur en arrière / en avant jusqu'à ce que le chemin (, true) soit appelé
la source
Bien que cet article soit ancien et ait eu une réponse acceptée, l'utilisation de reloadOnSeach = false ne résout pas le problème pour ceux d'entre nous qui ont besoin de changer le chemin réel et pas seulement les paramètres. Voici une solution simple à considérer:
Utilisez ng-include au lieu de ng-view et affectez votre contrôleur dans le modèle.
<!-- In your index.html - instead of using ng-view --> <div ng-include="templateUrl"></div> <!-- In your template specified by app.config --> <div ng-controller="MyController">{{variableInMyController}}</div> //in config $routeProvider .when('/my/page/route/:id', { templateUrl: 'myPage.html', }) //in top level controller with $route injected $scope.templateUrl = '' $scope.$on('$routeChangeSuccess',function(){ $scope.templateUrl = $route.current.templateUrl; }) //in controller that doesn't reload $scope.$on('$routeChangeSuccess',function(){ //update your scope based on new $routeParams })
Le seul inconvénient est que vous ne pouvez pas utiliser l'attribut de résolution, mais c'est assez facile à contourner. Vous devez également gérer l'état du contrôleur, comme la logique basée sur $ routeParams lorsque l'itinéraire change dans le contrôleur lorsque l'URL correspondante change.
Voici un exemple: http://plnkr.co/edit/WtAOm59CFcjafMmxBVOP?p=preview
la source
J'utilise cette solution
angular.module('reload-service.module', []) .factory('reloadService', function($route,$timeout, $location) { return { preventReload: function($scope, navigateCallback) { var lastRoute = $route.current; $scope.$on('$locationChangeSuccess', function() { if (lastRoute.$$route.templateUrl === $route.current.$$route.templateUrl) { var routeParams = angular.copy($route.current.params); $route.current = lastRoute; navigateCallback(routeParams); } }); } }; }) //usage .controller('noReloadController', function($scope, $routeParams, reloadService) { $scope.routeParams = $routeParams; reloadService.preventReload($scope, function(newParams) { $scope.routeParams = newParams; }); });
Cette approche préserve la fonctionnalité du bouton de retour et vous avez toujours le routeParams actuel dans le modèle, contrairement à certaines autres approches que j'ai vues.
la source
Les réponses ci-dessus, y compris celle de GitHub, ont eu des problèmes pour mon scénario et le bouton de retour ou le changement direct d'URL à partir du navigateur rechargeait le contrôleur, ce que je n'aimais pas. J'ai finalement opté pour l'approche suivante:
1. Définissez une propriété dans les définitions de route, appelée «noReload» pour les routes où vous ne voulez pas que le contrôleur se recharge lors du changement de route.
.when('/:param1/:param2?/:param3?', { templateUrl: 'home.html', controller: 'HomeController', controllerAs: 'vm', noReload: true })
2. Dans la fonction d'exécution de votre module, placez la logique qui vérifie ces routes. Il empêchera reload que si
noReload
esttrue
et contrôleur d'itinéraire précédent est le même.fooRun.$inject = ['$rootScope', '$route', '$routeParams']; function fooRun($rootScope, $route, $routeParams) { $rootScope.$on('$routeChangeStart', function (event, nextRoute, lastRoute) { if (lastRoute && nextRoute.noReload && lastRoute.controller === nextRoute.controller) { var un = $rootScope.$on('$locationChangeSuccess', function () { un(); // Broadcast routeUpdate if params changed. Also update // $routeParams accordingly if (!angular.equals($route.current.params, lastRoute.params)) { lastRoute.params = nextRoute.params; angular.copy(lastRoute.params, $routeParams); $rootScope.$broadcast('$routeUpdate', lastRoute); } // Prevent reload of controller by setting current // route to the previous one. $route.current = lastRoute; }); } }); }
3. Enfin, dans le contrôleur, écoutez l'événement $ routeUpdate afin de pouvoir faire tout ce que vous devez faire lorsque les paramètres d'itinéraire changent.
HomeController.$inject = ['$scope', '$routeParams']; function HomeController($scope, $routeParams) { //(...) $scope.$on("$routeUpdate", function handler(route) { // Do whatever you need to do with new $routeParams // You can also access the route from the parameter passed // to the event }); //(...) }
Gardez à l'esprit qu'avec cette approche, vous ne changez pas les choses dans le contrôleur, puis mettez à jour le chemin en conséquence. C'est l'inverse. Vous changez d'abord le chemin, puis écoutez l'événement $ routeUpdate pour changer les choses dans le contrôleur lorsque les paramètres d'itinéraire changent.
Cela garde les choses simples et cohérentes car vous pouvez utiliser la même logique à la fois lorsque vous changez simplement de chemin (mais sans requêtes $ http coûteuses si vous le souhaitez) et lorsque vous rechargez complètement le navigateur.
la source
Il existe un moyen simple de changer de chemin sans recharger
URL is - http://localhost:9000/#/edit_draft_inbox/1457
Utilisez ce code pour changer l'URL, la page ne sera pas redirigée
Le deuxième paramètre "faux" est très important.
$location.path('/edit_draft_inbox/'+id, false);
la source
Voici ma solution plus complète qui résout quelques problèmes que @Vigrond et @rahilwazir ont manqués:
$routeUpdate
.$locationChangeSuccess
n'est jamais déclenchée, ce qui empêche la mise à jour de la route suivante .Si dans le même cycle de résumé il y avait une autre demande de mise à jour, souhaitant cette fois recharger, le gestionnaire d'événements annulait ce rechargement.
app.run(['$rootScope', '$route', '$location', '$timeout', function ($rootScope, $route, $location, $timeout) { ['url', 'path'].forEach(function (method) { var original = $location[method]; var requestId = 0; $location[method] = function (param, reload) { // getter if (!param) return original.call($location); # only last call allowed to do things in one digest cycle var currentRequestId = ++requestId; if (reload === false) { var lastRoute = $route.current; // intercept ONLY the next $locateChangeSuccess var un = $rootScope.$on('$locationChangeSuccess', function () { un(); if (requestId !== currentRequestId) return; if (!angular.equals($route.current.params, lastRoute.params)) { // this should always be broadcast when params change $rootScope.$broadcast('$routeUpdate'); } var current = $route.current; $route.current = lastRoute; // make a route change to the previous route work $timeout(function() { if (requestId !== currentRequestId) return; $route.current = current; }); }); // if it didn't fire for some reason, don't intercept the next one $timeout(un); } return original.call($location, param); }; }); }]);
la source
path
de frappe à la finparam
, cela ne fonctionne pas non plus avec les hachages et l'url de ma barre d'adresse ne se met pas à jourAjouter la balise de tête intérieure suivante
<script type="text/javascript"> angular.element(document.getElementsByTagName('head')).append(angular.element('<base href="' + window.location.pathname + '" />')); </script>
Cela empêchera le rechargement.
la source
Depuis la version 1.2 environ, vous pouvez utiliser $ location.replace () :
$location.path('/items'); $location.replace();
la source
Je ne pouvais faire fonctionner aucune des réponses ici. En tant que piratage horrible, je stocke dans le stockage local un horodatage lorsque je change de route, et vérifie à l'initialisation de la page si cet horodatage est défini et récent, dans ce cas je ne déclenche pas certaines actions d'initialisation.
Dans le contrôleur:
window.localStorage['routeChangeWithoutReloadTimestamp'] = new Date().getTime(); $location.path(myURL);
Dans la configuration:
.when(myURL, { templateUrl: 'main.html', controller:'MainCtrl', controllerAs: 'vm', reloadOnSearch: false, resolve: { var routeChangeWithoutReloadTimestamp = window.localStorage['routeChangeWithoutReloadTimestamp']; var currentTimestamp = new Date().getTime(); if (!routeChangeWithoutReloadTimestamp || currentTimestamp - routeChangeWithoutReloadTimestamp >= 5000) { //initialization code here } //reset the timestamp to trigger initialization when needed window.localStorage['routeChangeWithoutReloadTimestamp'] = 0; } });
J'ai utilisé un horodatage plutôt qu'un booléen, juste au cas où le code serait interrompu avant d'avoir une chance de réinitier la valeur stockée avant de changer d'itinéraire. Le risque de collision entre les onglets est très faible.
la source