I have a controller, with a route like this:
#/articles/1234
I want to change the route without completely reloading the controller, so I can keep the positi
Better approach when using ngRoute:
/**
* Add skipReload() to $location service.
*
* See https://github.com/angular/angular.js/issues/1699
*/
app.factory('location',
['$rootScope', '$route', '$location',
function($rootScope, $route, $location) {
$location.skipReload = function() {
var lastRoute = $route.current;
var deregister = $rootScope.$on('$locationChangeSuccess',
function(e, absUrl, oldUrl) {
console.log('location.skipReload', 'absUrl:', absUrl, 'oldUrl:', oldUrl);
$route.current = lastRoute;
deregister();
});
return $location;
};
return $location;
}]);
How to use:
app.controller('MyCtrl', ['$scope', 'location', function($scope, location) {
$scope.submit = function() {
location.skipReload().path(path);
};
}]);
I have written a reusable factory for that based on Jens X Augustsson answer:
app.factory('DoNotReloadCurrentTemplate', ['$route', function($route) {
return function(scope) {
var lastRoute = $route.current;
scope.$on('$locationChangeSuccess', function() {
if (lastRoute.$$route.templateUrl === $route.current.$$route.templateUrl) {
console.log('DoNotReloadCurrentTemplate',
$route.current.$$route.templateUrl);
$route.current = lastRoute;
}
});
};
}]);
Works with AngularJS 1.0.6
How to use:
app.controller('MyCtrl',
['$scope', 'DoNotReloadCurrentTemplate',
function($scope, DoNotReloadCurrentTemplate) {
DoNotReloadCurrentTemplate($scope);
}]);
AngularJS issue here: https://github.com/angular/angular.js/issues/1699
You can do this without the $locationChange~
and HistoryState
hacks using route
s resolve promise option.
Assuming you had an article
route where that number is what changed you could do this;
$routeProvider.when(
'/article/:number',
{
templateUrl : 'partial.html',
controller : 'ArticleCtrl',
resolve : {
load : ['$q', '$routeParams', function($q, $routeParams) {
var defer = $q.defer();
//number was specified in the previous route parameters, means we were already on the article page
if ($routeParams.number)
//so dont reload the view
defer.reject('');
//otherwise, the number argument was missing, we came to this location from another route, load the view
else
defer.resolve();
return defer.promise;
}]
}
}
);
If you land here in 2015: The real answer here is to use none of these hacks (I dare name them so, because by using any of the methods listed above you will lose the possibility to use resolve and the likes) but to switch to ui-router.
Here's a handy presentation on the differences. Implementation should be as simple as swapping $route for $state and converting the states to names.
I'm currently switching over to a method where i will refer with an a href to a route, with an optional get parameter that changes the state without reloading it. For more on this, look at the 'params' section here
This simple solution (surprisingly) works for me:
$state.params.id = id; //updating the $state.params somehow prevents reloading the state
$location.path('/articles/' + id);
It doesn't prevent the state reloading on Back and forward button though. Note: I'm using angularjs 1.2.7 and ui-router 0.0.1 (I know it's old).
If you set reloadOnSearch to false, you can set the ?a=b&c=d
portion of the url without reload. You can't change the actual location prettily, though, without a reload.
Use:
$routeProvider.when('/somewhere', {
controller: 'SomeCtrl',
reloadOnSearch: false
})
This will prevent reloading the controller on query parameter change, but also on hash change.