After user logs out, I need to clean up my $rootScope. I tried $rootScope.$destroy() but that didn't do the trick. Is there a way to loop through all the values in $rootScope and delete them or a method to simply reset it?
You may wish to retain the default values that come with $rootScope when it is initialized. Since they all begin with a $ you can delete all the properties that don't start with $.
for (var prop in $rootScope) {
if (prop.substring(0,1) !== '$') {
delete $rootScope[prop];
}
}
You could make it easy to call by adding it as a function on $rootScope.
$rootScope.$resetScope = function() {
...
}
Indeed, the $destroy() method won't work on $rootScope (see here). I've worked around that by invoking $rootScope.$broadcast("$destroy") rather than .$destroy() when eliminating an entire Angular instance on our app. This way, all destructors are invoked the same.
As for the element $destroy event, I have to admit I wasn't even aware of it just a few days ago… I hadn't seen it anywhere in the docs, plus I'm using jQuery so according to here it wouldn't work for me anyway.
Reference from here
That is long description, But you can manually clear the RootScope by using this below ways
Option 1
Clear the rootScope variable
$rootScope.currentStatus = ""; //or undefined
Option 2
if you want to remove whole $rootscope objects,
$rootScope=undefined //or empty
To delete a variable from rootScope
delete $rootScope.variablename
Related
I want to access this in only one controller if I move to another component I want to remove this value and make it null
this.$rootScope.selectedPage = page;
You can call $onDestroy inside your controller, and remove that value there
$onDestroy() - Called on a controller when its containing scope is destroyed. Use this hook for releasing external resources, watches and event handlers
e.g.
$scope.$onDestroy = function() {
this.$rootScope.selectedPage = null; // or delete it altogether
};
EDIT:
However, if you just need that one variable in just one controller you should just bind it to $scope and avoid $rootScope, that way angularjs will free it by itself.
$scope.selectedPage = ...
General rule of thumb is to avoid $rootScope if you can.
I have an AngularJs component having bindings to heroes, which is an array. How to watch this input for array changes? I tried $scope.watch("heroes", ...) and $onChanges, but didn't work so far.
bindings: {
heroes: '<',
}
Here is my plunker: https://plnkr.co/edit/J8xeqEQftGq3ULazk8mS?p=preview
The ControllerAs structure needs a special watch expression, since the attributes are not on the $scope.
//This one works and is the best one (> AngularJs 1.5)
$scope.$watch("$ctrl.heroes.length", function () {
console.log("ControllerAs syntax"); // Triggers once on init
});
//This one works as well
var ctrl = this;
$scope.$watch(() => {
return ctrl.heroes.length;
}, (value) => {
console.log("complex watch"); // Triggers once on init
});
See example here: https://plnkr.co/edit/J8xeqEQftGq3ULazk8mS?p=preview
The issue occurs because $scope.$watch by default doesn't deeply watch objects. Which means since you never destroy/recreate your array, the reference doesnt really change therefore $scope.$watch doesnt see any change. If you watched heroes.length, that primitive would change and your $scope.$watch would fire the corresponding listening function. By using $scope.$watch with the true option you are telling the angular engine to deeply watch all properties.
This is pretty intensive to do for large objects because $scope.$watch using angular.copy to track changes
If you were to use $scope.$watchCollection angular would create a shallow copy and would be less memory intensive. So I feel your 3 main options are
Watch heroes.length , add true or use $watchCollection
I feel that using heroes.length would be your best bet, so the code would look like
$scope.$watch('heroes.length',function(){});
The other two options are described below
$scope.$watch('heroes',function(){
//do somthing
},true)
or
$scope.$watchCollection
The benefit of using watchCollection is, that it requires less memory to deeply watch an object.
Shallow watches the properties of an object and fires whenever any of
the properties change (for arrays, this implies watching the array
items; for object maps, this implies watching the properties). If a
change is detected, the listener callback is fired.
The obj collection is observed via standard $watch operation and is
examined on every call to $digest() to see if any items have been
added, removed, or moved. The listener is called whenever anything
within the obj has changed. Examples include adding, removing, and
moving items belonging to an object or array.
I need to clear all the $scope values while performing some operations.
For eg: If I Click a "Signout" button to redirect to "signin" page, then all the $scope or $rootScope values in the session should be cleared.
How can I achieve this?
You can do the following:
$rootScope = $rootScope.$new(true);
$scope = $scope.$new(true);
The function $new is creating a new scope inheriting the variables from the parent. true prevents the inheritance.
But this is not the correct approach, because if you use the thing above, you should bootstrap the controllers functions manually and recreating the tree of scopes.
This might be useful though, where the idea is to store the initialized data is stored in some variables and then, when assigned copied to the displayed variables.
The correct solution is to clear manually every property in each scope on the logout event like this:
Logout event:
$rootScope.$broadcast("logout");
Catching the event:
$rootScope.$on("logout", function(){
$rootScope.myData = undefined;
});
Or as suggested in the comments, to use a service and then be cleaned.
You not want delete scope
var authScope =['authLogo','currentPath','pageTitle','app'];
for (var prop in $rootScope) {
if (prop.substring(0,1) !== '$') {
if(authScope.indexOf(prop) ==-1)
delete $rootScope[prop];
}
}
I have the following $rootScope variable which I use to save the current logged in user privilege level, then I access this variable from other controllers. Is there a way I can watch the rootScope variable for changes in order to update controllers specific variables with any changes to the root scope variable? Below is the code I am using so far, can someone please tell me what I am doing wrong and how to fix it? Thanks
In app.js under .run:
$rootScope.uPLevel = 0;
.controller
$scope.$watch($rootScope.uPLevel, function() {
$scope.userPLevel = $rootScope.uPLevel;
}, true);
The first parameter to $watch should either be a string or a function (docs). Right now you're passing it the value of $rootScope.uPLevel on controller initialization.
$scope.$watch(function() {
return $rootScope.uPLevel;
}, function() {
$scope.userPLevel = $rootScope.uPLevel;
}, true);
Two sidenotes:
It may be prudent to store this value in a service instead of $rootScope.
If uPLevel is only an integer (as your example suggests) then you don't need to pass true as the third parameter - that's only for arrays and objects. If you do want to watch a collection, then I suggest using $watchCollection instead.
I recommend watching $rootScope variables like that:
$scope.$watch('$root.uPLevel', function() {
$scope.userPLevel = $rootScope.uPLevel;
});
This way, When current directive/controller is destroyed. It clears the watch as well. In $rootScope.$watch case, the watch stays forever.
I'm having an issue getting a watch to work within a directive. I've put together a simple example here. http://plnkr.co/edit/A7zbrsh8gJhdpM30ZH2P
I have a service and two directives. One directive changes a property in the service, and another directive has a watch on that property. I expected the watch to fire when the property is changed but it doesn't.
I've seen a few other questions like this on the site, but the accepted solutions on them have not worked here. I've considered using $broadcast or trying to implement an observer, but it seems like this should work and I don't want to over complicate things if possible.
Mark Rajcok' answer is incomplete. Even with angular.copy(), $watch listener will be called once and never again.
You need to $watch a function:
$scope.$watch(
// This is the important part
function() {
return demoService.currentObject;
},
function(newValue, oldValue) {
console.log('demoService.currentObject has been changed');
// Do whatever you want with demoService.currenctObject
},
true
);
Here the plunker that works: http://plnkr.co/edit/0mav32?p=preview
Open your browser console to see that both the directive and the demoService2 are notified about demoService.currentObject changes.
And btw angular.copy() is not even needed in this example.
Instead of
this.currentObject = newObject;
use
angular.copy(newObject, this.currentObject);
With the original code, the viewer directive is watching the original object, {}. When currentObject is set to newObject, the $watch is still looking for a change to the original object, not newObject.
angular.copy() modifies the original object, so the $watch sees that change.