Can you change a path without reloading the controller in AngularJS?

If you don't have to use URLs like #/item/{{item.id}}/foo and #/item/{{item.id}}/bar but #/item/{{item.id}}/?foo and #/item/{{item.id}}/?bar instead, you can set up your route for /item/{{item.id}}/ to have reloadOnSearch set to false (https://docs.angularjs.org/api/ngRoute/provider/$routeProvider). That tells AngularJS to not reload the view if the search part of the url changes.


If you need to change the path, add this after your .config in your app file. Then you can do $location.path('/sampleurl', false); to prevent reloading

app.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]);
    };
}])

Credit goes to https://www.consolelog.io/angularjs-change-path-without-reloading for the most elegant solution I've found.


why not just put the ng-controller one level higher,

<body ng-controller="ProjectController">
    <div ng-view><div>

And don't set controller in the route,

.when('/', { templateUrl: "abc.html" })

it works for me.


For those who need path() change without controllers reload - Here is plugin: https://github.com/anglibs/angular-location-update

Usage:

$location.update_path('/notes/1');

Based on https://stackoverflow.com/a/24102139/1751321

P.S. This solution https://stackoverflow.com/a/24102139/1751321 contains bug after path(, false) called - it will break browser navigation back/forward until path(, true) called


Though this post is old and has had an answer accepted, using reloadOnSeach=false does not solve the problem for those of us who need to change actual path and not just the params. Here's a simple solution to consider:

Use ng-include instead of ng-view and assign your controller in the template.

<!-- 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
})

Only down-side is that you cannot use resolve attribute, but that's pretty easy to get around. Also you have to manage the state of the controller, like logic based on $routeParams as the route changes within the controller as the corresponding url changes.

Here's an example: http://plnkr.co/edit/WtAOm59CFcjafMmxBVOP?p=preview