Angular $watch function not working as intended - angularjs

So I have the following watcher on a scope in the link function of a directive. I have used this pattern for another variable and it works however this one does not. Does anyone have any suggestions. Code is as follows
$scope.$watch('QOLFactory.surveysInView', function(newValue, oldValue, scope){
console.log(QOLFactory.surveysInView);
console.log(newValue, oldValue);
scope.surveys = newValue;
scope.surveyData = generateSurveyTotals(newValue);
});
The first console log prints the corrent value of QOLFactory.surveysInView, but the second console.log prints undefined, undefined. Is there something that I am doing wrong?
Thanks in advance.

In order for the watcher on directive to have access to the Service that was being injected in the controller, the Service has to be assigned to $scope variable. This makes the watcher behave as expected, and returns the correct values.

Related

What is the purpose of $watch in angularjs

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

What does angular $watch do when no return value from the function it monitor

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

Directive not updated after factory call

I have a custom directive that has a single attribute called content. I'm trying to pass data to this directive's attribute via an outer's controller scope variable called x. This seems to work fine by setting x equal to 'xyz' at the start of the controller, but when I make a call to a factory to pull a value to update the x variable the data isn't being reflected in the directive. I can see that $scope.x is being set to the return value from the factory within the controller, but it's not then updating the directive.
I seem to missing something somewhere. I'm guessing it's a scope problem but I'm just not seeing it. I've tried to simplify my issue into a Plunker (http://plnkr.co/edit/wsWzSTJ9VDprfTaToeHv).
Any thoughts?
Thanks
Chris
The basic problem as noted in the comments is a missing $watch in the directive controller.. the controller doesn't "know" that content variable has changed..
so adding a $watch in the controller (the directive controller!) would solve this:
$scope.$watch(function(){return $scope.content}, function(){
$scope.text = $scope.content
})
A working demo
Good luck!

How to execute a function when a value change?

I've a main controller and into it two other controllers:
<div ng-controller="mainController" ng-model="value">
<div ng-controller="otherController"></diV>
<div ng-controller="anOtherController"></div>
</div>
Thanks to the controller inheritance my otherController can update my value I bind with the ng-model diretive.
But how can I notice my anOtherController that the value have changed in order to execute a function owned by anOtherController?
Can I register a function to this value?
You can do this in your controller..
$scope.$watch("value",function(newValue,oldValue){
// your code goes here...
});
It will basically watch for any changes on a given "scope property". However, my advice is to use a either a service or a factory.
Please refer to this other SO Discussion:
AngularJS Service Passing Data Between Controllers
Send a message to the other scopes:
$scope.$broadcast('messagename', params);
To catch it:
$scope.$on('messagename', function(params){
alert('something happend');
});
The scope inherits downwards; if you want the message to be sent to all scopes, use $rootScope.$broadcast.
Or you can simply add a watcher.
You need to be careful here:
mainController will have a scope.value
otherController and anOtherController won't have a scope.value defined, although if you try to access scope.value it will work since they are children of mainController so it will transverse the prototype chain to find that property. However, when you assign a value into scope.value in otherController/anOtherController , you are defining a local version of that variable in your scope and it will differ from the other controllers.
If you genuinely want to modify the same element for the three elements you will need to assign new values to the parent scope property in the children controllers.
For example:
if scope.value was equal to "old" in maincontroller:
in otherController:
$scope.$parent.value = "new"
in anOtherController or mainController:
console.log($scope.value) // "new"
But if you do:
in otherController:
$scope.value = "new"
in anOtherController or mainController:
console.log($scope.value) // "old"
Now, knowing all this and answering your question if you want to execute a function everytime scope.value changes in anOtherController and you are not going to modify that property in that scope you can get away with:
Inside anOtherController:
$scope.watch('value', function(newVal, oldVal) {
myfunc();
}
But you need to make sure that you don't assign values to $scope.value instead assign them to $scope.$parent.value.

AngularJS $watch root scope variable for changes

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.

Resources