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.
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.
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
In angularJs: what's the different between setting $watch on string variable and setting $watch on Object's key?
The detail scenario is as follow:
$scope.activedMenu = {'id' : '...', 'name' : 'menu1'};
$scope.selectedMenuName = 'menu1';
$scope.$watch('activedMenu.name', function () {...});
$scope.$watch('selectedMenuName', function () {...});
So, my question is what's the different between "$scope.$watch('activedMenu.name', function () {...})" with "$scope.$watch('selectedMenuName', function () {...})"? Any help will be appreciated!
(I think these two ways to set a $watch are equivalence, I refer from the scope develop guide! https://docs.angularjs.org/guide/scope)
Basically $watch need string parameter & search for that parameter inside current scope & placed dirty watch on it.
Watching on activedMenu.name OR selectedMenuName is one as the same thing, 1st one will watch on name property of activedMenu, the 2nd one will watch on selectedMenuName scope variable.
The only difference I think is you are watching on single property so you can use object equality option here which deep watches the object change. It could be possible for you 1st watch but watch string should be activedMenu only
$scope.$watch('activedMenu', function(newVal, oldVal){
//on watch code here
}, true);
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 am trying to persist the whole scope to a service so that it is available and already set up after user navigates away and then returns to the screen.
I have created a service and am storing the current scope there. Later I set the $scope variable passed into the controller with the one stored in my service, but the after inspecting the DOM, I see that it's bound scope is still the scope object that existed before replacing.
How can I replace the scope so that it will also be used for the DOM elements?
Thanks for any help!
the below code tries to see if the local scope variable is initialized and if so it sets the $scope to it, otherwise it continues and wires it all up normally. this.scope is a member variable defined and set in the controller's super class (not shown).
function xyzController($scope, stateService) {
_super.call(this, $scope, stateService);
if (this.scope.hasBeenInitialized) {
$scope = this.scope; // $scope is updated but the DOM's scope never changed
return;
}
$scope.hasBeenInitialized = true;
...
}
You could try:
if (this.scope.hasBeenInitialized) {
angular.extend($scope, this.scope);
return;
}
This would merge the values from this.scope onto your $scope without replacing the variable.
This won't work. Scope is wired up deep inside Angular. To give you an idea, on any element, you can call:
angular.element(someDomElement).scope();
And get its scope. It's really not do-able to replace scopes like you're trying to do. But the more immediate problem is you're just overwriting that particular variable. It's an object passed in. Imagine you have this code:
var myObject = { a: 1 };
function f(obj) {
obj = { a: 2 };
}
f(myObject);
Clearly this doesn't change myObject. It'll replace obj within your function, but the thing about scopes is they're set up for you for all the expression in your views (it's the this in any scope functions for example). You'd need to change it through and through, and I don't see a way to do that.