AngularJs location path change without all controllers resetting

All we need is an easy explanation of the problem, so here it is.

Short version of my question is: How do I change the URL without need to trigger route change or without need to run all the controllers on the currently displayed page?

Details:

I have a template which is displayed inside the <ng-view> that has regions governed by 3 controllers. On the very top of the page I have an interactive map. When you click on the regions it broadcasts a click and other component picks up on it and displays data about this region. Really simple setup.

What I would like to do is allow my users to deep link to the content. So every time someone clicks on a link I’d like to change the URL that can be copied and pasted to another browser. Some other user could just click the link and see the same state the first one saw.

Currently I change the location with code similar to this one:

  $scope.$on('mapRegionClick', function($scope, regionCode) {
    var url = generateURL(regionCode);

    $scope.currentScope.$apply(function(){
      $location.path(url);
    });});

The URL is then picked up in my routing and the map plus data displays correctly. The downside of this is that every time I click on the map and URL changes the whole template / view is regenerated. Because generating the map is kind of heavy I’d like to trigger only a change to the data presenting controller.

Is it possible? How?

I could do some communication between controllers and achieve the my goal but then I would not be able to do deep linking.

PS: I do not want to use $location.search() and reloadOnSearch=false. my links have to be pretty 🙂

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Sounds like you don’t want to use $route service.

The $route service is designed to reload the controllers so that there is no difference between navigating to a URL and refreshing the URL. We do this by doing a full reload on every URL change. This is intentional.

Sounds like your use case, should not be using $route, just $location and ng-include.

Method 2

You can use $locationChangeStart event to store the previous value in $rootScope or in a service. When you come back, just initialize all the previously stored values from the $rootScope. Check this quick demo using $rootScope.

enter image description here

var app = angular.module("myApp", ["ngRoute"]);
app.controller("tab1Ctrl", function($scope, $rootScope) {
    if ($rootScope.savedScopes) {
        for (key in $rootScope.savedScopes) {
            $scope[key] = $rootScope.savedScopes[key];
        }
    }
    $scope.$on('$locationChangeStart', function(event, next, current) {
        $rootScope.savedScopes = {
            name: $scope.name,
            age: $scope.age
        };
    });
});
app.controller("tab2Ctrl", function($scope) {
    $scope.language = "English";
});
app.config(function($routeProvider) {
    $routeProvider
        .when("/", {
            template: "<h2>Tab1 content</h2>Name: <input ng-model='name'/><br/><br/>Age: <input type='number' ng-model='age' /><h4 style='color: red'>Fill the details and click on Tab2</h4>",
            controller: "tab1Ctrl"
        })
        .when("/tab2", {
            template: "<h2>Tab2 content</h2> My language: {{language}}<h4 style='color: red'>Now go back to Tab1</h4>",
            controller: "tab2Ctrl"
        });
});
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular-route.js"></script>
<body ng-app="myApp">
    <a href="#/!" rel="nofollow noreferrer noopener">Tab1</a>
    <a href="#!tab2" rel="nofollow noreferrer noopener">Tab2</a>
    <div ng-view></div>
</body>
</html>

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply