I use UI-Router
routing. When I change path from a state to another and going back to same state, I see that old $scope in state is there (with it's properties).
I want to destroy that $scope before state changes, So when I come back to state for second time, there will be a clean new scope. I tried to access scope in this event:
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams) {
// fromState.$scope.$destroy();
});
But there isn't any reference to $scope. Can I access scope before change state in angular UI-Router
?
I would say, that what you experience is a bit different than you described, or you thought what is happening. Please, check for example this:
In general, once the state change is done (not rejected), the old $scope is for sure destroyed. If we navigate then back, new $scope
is created for us. But this $scope is created this way:
The source code of theviewDirective.js
function updateView(firstTime) {
var newScope,
name = getUiViewName(scope, attrs, $element, $interpolate),
previousLocals = name && $state.$current && $state.$current.locals[name];
if (!firstTime && previousLocals === latestLocals) return; // nothing to do
// HERE
newScope = scope.$new();
...
The construct: scope.$new();
is a key to understanding. This in fact means, that we use prototypical inheritance
And that in a nutshell could be described:
we are provided with a
$scope
which has cloned all the properties from its parent.
So if parent contains some reference (has '.' in the path) like this
// parent scope
$scope.Model = {
...
};
And any child state will change that like this
$scope.Model.name = "User";
That value will be stored in parent state $scope and available again ... for any next child of this state.
NOTE: the same viewDirective.js but elswhere could be used to demonstrate the fact - $scope is destroyed
if we leave the state:
function cleanupLastView() {
if (previousEl) {
previousEl.remove();
previousEl = null;
}
if (currentScope) {
currentScope.$destroy();
currentScope = null;
}
...
EXTEND
I created a working example here, with these two states:
.controller('ParentCtrl', ['$scope', function ($scope) {
$scope.Model = {
SharedName: "This is shared name",
}
$scope.NotSharedName = $scope.NotSharedName
|| "This name is cloned, but then lives its own way";
}])
.controller('ChildCtrl', ['$scope', function ($scope) {}])
And these two ways how to change values (all will follow the logic described above):
<p>this will be shared among all children and parent
<input ng-model="Model.SharedName" />
</p>
<p>this will always copied from parent, live then in each child
<input ng-model="NotSharedName" />
</p>
Check it here
I was going to make an add-on comment on Radim Köhler's post but since I don't have enough rep points, I'll just add an answer here that the only solution I've used so far to circumvent this is to use the "controller as" approach and avoid adding methods/properties on the controller scope that I don't want conflicting due to prototypal behavior.
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