What is the purpose of $watch in angularjs. Can anyone explain me how it works and what is the purpose of $watch. Thanks in advance
The $scope.watch() function creates a watch of some variable. When you register a watch you pass two functions as parameters to the $watch() function:
A value function
A listener function
Here is an example:
$scope.$watch(function() {},
function() {}
);
The first function is the value function and the second function is the listener function.
The value function should return the value which is being watched. AngularJS can then check the value returned against the value the watch function returned the last time. That way AngularJS can determine if the value has changed. Here is an example:
$scope.$watch(function(scope) { return scope.data.myVar },
function() {}
);
This example valule function returns the $scope variable scope.data.myVar. If the value of this variable changes, a different value will be returned, and AngularJS will call the listener function.
The listener function should do whatever it needs to do if the value has changed. Perhaps you need to change the content of another variable, or set the content of an HTML element or something. Here is an example:
$scope.$watch(function(scope) { return scope.data.myVar },
function(newValue, oldValue) {
document.getElementById("").innerHTML =
"" + newValue + "";
}
);
This example sets the inner HTML of an HTML element to the new value of the variable, embedded in the b element which makes the value bold. Of course you could have done this using the code {{ data.myVar }, but this is just an example of what you can do inside the listener function.
Hope help ful to you.
Take a look at the Angular docs, they are generally pretty good and include examples.
$watch(watchExpression, listener, [objectEquality]);
Registers a listener callback to be executed whenever the
watchExpression changes.
https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch
Related
All:
I am pretty new to Angular, when I tried to understand how ngStorage works, there is some code in its source like:
$rootScope.$watch(function() {
_debounce || (_debounce = $timeout($storage.$apply, 100, false));
});
From Angular Scope Doc:
$watch(watchExpression, listener, [objectEquality]);
Expression that is evaluated on each $digest cycle. A change in the
return value triggers a call to the listener.
string: Evaluated as expression
function(scope): called with current scope as a parameter.
Both ways need some return value to trigger a listener, but in this example, there is no return value nor listener, so I kinda wondering what this code do?
Or if anyone could briefly talk about how ngStorage works?
Thanks
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've been trying to understand $watch function on $scope object. This looks pretty straight forward but the thing that I don't understand is why (on page load) listener function is being executed when I pass a non existing $scope object variable in value function.
$scope.$watch ('nonExistingVariableIdentifier', function () { console.log('Variable value changed'); });
Am I missing something?
The watch runs when it is created.
The full use of a $watch is:
$scope.$watch("nonExistantVariable", function(newValue, oldValue) {
if (newValue == oldValue) {
// First run
}
else {
// After First run
}
})
This is the correct way to differentiate between the initialization and an actual change.
After a watcher is registered with the scope, the listener fn is called asynchronously (via $evalAsync) to initialize the watcher. In rare cases, this is undesirable because the listener is called when the result of watchExpression didn't change. To detect this scenario within the listener fn, you can compare the newVal and oldVal. If these two values are identical (===) then the listener was called due to initialization.
From the Angular JS Docs for $watch - Docs
This is some logic in a controller:
function newGame(){
$scope.gameOver = true;
$timeout(function(){
//do stuff
$scope.gameOver = false;
}, 3000);
}
In a directive I have:
scope.$watch(scope.gameOver,function(){ console.log("changed!", scope.gameOver);})
I'd like to do something based on scope.gameOver. I use the timeout function to give the game 3 seconds of time where gameOver = true. However, watch does nothing during those 3 seconds and instead fires off at the end of those 3 seconds where scope.gameOver has already been turned back into false.
What is the proper way of doing this?
Your $watch callback function will be invoked at least once when the $watch is set up, irrespective of whether or not your scope.gameOver variable changes.
This is pointed out in the official documentation:
After a watcher is registered with the scope, the listener fn is called asynchronously (via $evalAsync) to initialize the watcher.
I think you may be running into unexpected behaviour because you are specifying to $watch a primitive value instead of a reference to the variable holding the value of interest.
In other words,
scope.$watch(scope.gameOver, function() { ... });
as you have specified, would be the same as,
scope.$watch(true, function() { ... });
which obviously will not do anything productive.
Instead, prefer specifying your $watch using a function to return a reference to scope.gameOver or alternatively take advantage of how the variable to $watch can be an Angular expression:
// Function to return reference to the variable to watch
scope.$watch(function() { return scope.gameOver; }, function() { ... });
// Expression for Angular to evaluate
scope.$watch('gameOver', function() { ... });
Hope that helps.
Watch will be triggered only when the watch parameter changes. So in your code the $scope.gameOver
changes only at the end of 3 seconds and hence the watch is triggered.
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.