I am using service to communicate between the controllers, while using $watch in my controller, i am able to use it in two ways
service.coffee
myContent = null
getContent = ->
return myContent
setContent = (data) ->
myContent = data
return myContent
my controller:
$scope.test = myService
$scope.$watch "test.getContent()", ->
if $scope.test.getContent() is 'data'
console.log 'yes'
Also,
$scope.$watch (->
test.getContent()
), (value) ->
if value is 'data'
console.log 'yes'
Both gives the expected result, but i would like to know whats the difference between the two methods and in which scenerio we should use the same
Consult the Angular Documentation on $rootScope for a more in-depth answer.
$scope.$watch() takes three arguments, where watchExpression is the first. watchExpression can be either a string or a function. If it is a string, it is evaluated in the $scope in question.
This allows us to easily listen to values on the scope:
$scope.someValue = 2;
$scope.$watch('someValue', function(someValue) {
// some function
});
In your case, you could simply pass it the function:
$scope.$watch($scope.test.getContent, ...);
To sum up, pass a function when the result of it is what you want to watch, or pass an expression if that makes more sense (in most cases, it probably will). It makes little sense to pass a string expression evaluating to the result of some function already available, especially taking into account that the expression would have to be parsed, causing an extra overhead.
No difference actually. The first parameter of $watch function is either a String or a function. If you pass a string as the first parameter for $watch, Angular will automatically parse the string into a function taking the $scope as the function context.
So you can take the following piece of code
$scope.$watch("book", function(){...});
as
$scope.$watch(function(){return $scope.book;}, function(){...});
They are internal equivalent.
Related
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
I have a string reference to one of my scope values like this:
var reference_string = "form.name";
And I want to assign a value to the object it is referencing:
$scope.form.name = 'newvalue';
Looking around, I found 2 possible solutions: using plain JS or using the angular $parse function.
However, it seems like the $parse function only returns the value. Can I make it so that I can assign a new value?
ie. I want to do something like
var reference_string = "form.name";
var reference = getReference($scope, reference_string); // ideally using an angular in-built function like $parse
reference = 'newvalue'; // should have the same effect as $scope.form.name = 'newvalue';
The object returned by $parse has an assign() method for setting values.
var getter = $parse(reference_string);
getter.assign($scope, 'newValue');
Plunker demo ~ http://plnkr.co/edit/RlhXRpJvQ69ZdEkstyq8?p=preview
$parse is an Angular service which converts an expression into a function. The function can then be invoked and passed a context (usually scope) in order to retrieve the expression's value.
In addition, if the expression is assignable the returned function will have an assign property. The assign property is a function that can be used to change the expression's value on the given context.
enter link description here
I have a function being used in my service that is defined as:
var getData = function() {
return anotherService.getData().$promise;
};
and a this property that I manipulate throughout the service.
this.someProperty = 'a string';
I call the above function inside the return section of my service:
return{
updateProperty: function(){
getData().then(function(data){
this.someProperty = data;
});
}
}
In the above, I get an this is undefined related error in my browser console. I assume this is because the resolved $promise is an AJAX call and this is used out of context. What's the best way to manipulate a this property using the returned data from an AJAX call in this instance?
if you're manipulating this throughout your service, assign it to a variable like var self = this. The problem is that this is the context of a function and can be changed by other code using fn.call(context) or fn.apply(context, args). So it's liable to be different inside of the scope of any given function.
So just assign it to some variable and use it:
var self = this;
return {
updateProperty: function(){
getData().then(function(data){
self.someProperty = data;
});
}
};
The simplest way would be to use the bind function. This function sets the 'this' context for the function call. So, in your case you'd have to use it twice so that the proper 'this' populates in.
return{
updateProperty: function(){
getData().then((function(data){
this.someProperty = data;
}).bind(this));
}
}
This comes to ensure that the handler you passed to the promise is executed with the original 'this' (passed to updateProperty). Now, to pass the correct 'this' value to the updateProperty function, you should, in your controller do:
(myService.updateProperty.bind(this))();
There are numerous versions of binding, including binding the entire service. Also, have a look at lodash for function extensions.
I prepared a small pen to demonstrate this. It covers what I listed above, plus another important thing to note. When you use setTimeout, the handler is invoked with in the global context (in this case, 'window'), this is why I added a third bind, to make sure 'this' is relevant inside the timeout handler. I also added various count increment calls to demonstrate that 'this' is the same value along the way.
If this is a repeating scenario, you might want to pass either the target object (and then use the handler just to know it was updated), or a handler (which also needs binding). I added examples for these scenarios as well.
One last word, call, apply and bind are key to javascript and worth learning. Put some time into it and work your way out of context hell.
I've built a directive that gets its data by $parse'ing from an Angular expression in one of my $attrs. The expression is typically a simple filter applied to a list model, the evaluation of which will change when the parent $scope is modified.
To monitor when it should update the data it's using, my directive is using a $scope.$watch call, with a custom function that re-$parse's the expression. The problem I'm running into is that $parse will generate a new object instance from the expression, so $watch sees the value as changed even when the data in each object is completely equivalent. This results in my code hitting the $digest iteration cap very quickly due to actions taken in the $watch callback.
To get around this I am doing the following, currently:
var getter = $parse($attrs.myExpression);
$scope.$watch(function () {
var newVal = getter($scope);
if (JSON.stringify($scope.currentData) !== JSON.stringify(newVal)) {
return newVal;
} else {
return $scope.currentData;
}
}, function (newVal) {
$scope.currentData = newVal;
// other stuff
});
However, I don't like relying on JSON as an intermediary here, nor using my $watch'ed function itself to evaluate equivalency of old and new values. Is there a flag the $watch can take to determine if two objects are equivalent, or is there a better approach for handling this kind of situation?
Hi you should use this,
scope.$watch('data', function (newVal) { /*...*/ }, true);
This has been answerd here on stackoverflow
$scope.myFunc = function(privilege){
$scope.check = function(privilege){
return ...
};
$scope.$watch('check(privilege)',function(val){
...
}
}
My privilege variable becomes undefined at every watch check(which must not be)? Why I should define it scope variable or do I miss anything with Angular Js?
The first parameter of the $watch method (the "watchExpression") can be either an Angular string expression (that is evaluated against the $scope), or a function, which is called with $scope as the first parameter. There is no way to pass privilege as the first argument to a watchExpression that is a function.
You could create a closure, if you don't want to store the privilege value on the $scope. See Vojta's fiddle for an example.
See also https://groups.google.com/forum/#!msg/angular/UJRxn_Y0Dd4/9ha38PC3PCwJ