It seems, by default, the controller of the previous state is reloaded when you press the back button in the browser to go to a previous state. (this is not true in case of parent-child states)
How can I prevent that from happening?
Since I am not going to change any data in my current state which can affect the previous state, I don't want the previous state to reload again.
Here is a small plunker: http://plnkr.co/edit/xkQcEywRZVFmavW6eRGq?p=preview
There are 2 states: home
and about
. If you go to about
state and then press back button, you will see that the home
state controller is called again.
.state('home', {
url: '/home',
templateUrl: 'partial-home.html',
controller: function($scope) {
console.log('i was called');
}
})
I believe this is the expected behavior, but I want to prevent it because my previous state (home
in this case) is doing some visualizations which take some time to be created again.
Let's start with a global controller like GlobalCtrl
which is added to the <body>
or <html>
tag like ng-controller="GlobalCtrl
.
Doing this will enable us to keep the scope of this GlobalCtrl
throughout your single page Angular app (as you are using ui-router).
Now, inside your GlobalCtrl
define something like this:
$rootScope.globalData = {preventExecution: false};
// This callback will be called everytime you change a page using ui-router state
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState) {
$scope.globalData.preventExecution = false;
// Just check for your states here
if (toState.name == "home" && fromState.name == "about") {
$scope.globalData.preventExecution = true;
}
});
Now, in your state configuration, you can use this $scope.globalData.preventExecution;
.state('home', {
url: '/home',
templateUrl: 'partial-home.html',
controller: function($scope) {
if ($scope.globalData.preventExecution) {
return;
}
console.log('i was called');
}
});
Answer to the question: The scope that we refer in the GlobalCtrl and the scope that we use in the State controller, how are they related?
Well, it is a very good question but it's simple. Every time a new scope is created in Angular, it always inherits its parent scope (unless isolated). So when your home
state controller instantiated, its scope created using parent state i.e. $rootScope
here in this case and we are instantiating the globalData
in the $rootScope
which is an Object (an Object
in Javascript can be used to it's any nested object. Read this). So now when we are setting the globalData.preventExecution
true/false
, the same data can be used in the $scope
of your home
state controller. This is how both scopes are related or using the same data.
Answer to the question: is there some flag or setting in the ui-router which can accomplish this in general
If you want to achieve the above behaviour code for multiple states then you can write something like this:
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState) {
$scope.globalData.preventExecution = false;
if (toState.name == "home" && fromState && fromState.preventHomeReExecution) {
$scope.globalData.preventExecution = true;
}
});
Now, your states can be written like this:
.state('about', {
url: '/about',
templateUrl: 'partial-about.html',
preventHomeReExecution: true
})
.state('foo', {
url: '/foo',
templateUrl: 'partial-foo.html',
})
.state('bar', {
url: '/bar',
templateUrl: 'partial-bar.html'
preventHomeReExecution: true
})
Basically, we are using preventHomeReExecution: true
as a flag you wanted.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With