$watch in angularJS is not working as expected - javascript

In my controller I want to be notified when a variable value is changed. My requirement is when value of a variable will change a function will be invoked. So I am using $watch. My code is as follow.
var Canvas = angular.module('canvas');
Canvas.controller("excelOperation",function($scope,Data,SharedData,$http){
$scope.tbody=$scope.$parent.shared.previews;
$scope.$watch('$parent.shared.previews',function(newVal,oldVal){
console.log("WORKING");
})
setInterval(function(){
console.log($scope.$parent.shared.previews);
},1000)
/**
* Populate table function to populate excel table
*/
$scope.populateTable=function()
{
}
})
angular.bootstrap(document.getElementById("page"), ['canvas']);
But issue is $watch is working only when I refresh my page. Though the setInterval is printing the changed value of the variable $watch is not being invoked.
N.B. $scope.$parent.shared.previews is an object
What am I doing wrong?
And what I told to achieve, is this a good way to do?

You are watching a object's property change, deep watch is required. Second, to watch parent scope variable, maybe you'd better write like this $scope.$parent.$watch(...).
var deepWatch = true;
$scope.$watch('$parent.shared.previews', function(newVal, oldVal) {
console.log("WORKING");
}, deepWatch);

Related

AngularJS track global variable change in a controller

I am using Angular v1.3.13.
I need to watch a global variable in order to enable/disable certain buttons in the template view. I know the global variable is changing based on console.log output but its not updating in the controller...or I am not watching it properly.
While in this controller I need to initiate the $watch and keep watching while the user stays in this view/controller.
$scope.$on('$ionicView.beforeEnter', function () {
var gpsTracker = this;
gpsTracker.gpsEnabled = mapInfo.gpsEnabled;
$scope.$watch(angular.bind(this, function (gpsEnabled) {
return this.gpsEnabled;
}, function () {
getLocationAuth()
}));
});
I have tried several iterations but nothing has worked. The object variable mapInfo.gpsEnabled is what I am try to track.

How to stop $watch when change the object vlaue on second time

How to stop $watch while changing the object
Here is a $watch function
$scope.$watch($scope.OneTime,function(old,new)
{
// my function
});
The above $watch function will be fire whenever my (OneTime) object value has been changed.
But I won't to watch the object on every change, I just want to fire the $watch function when I change the my object on first time only.
I also tried something and find out a function from angular.js script file But I don't know what the below function doing exactly.
You can find this function from angular.js script file
function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {
var unwatch, lastValue;
return unwatch = scope.$watch(function oneTimeWatch(scope) {
return parsedExpression(scope);
}, function oneTimeListener(value, old, scope) {
lastValue = value;
if (isFunction(listener)) {
listener.apply(this, arguments);
}
if (isDefined(value)) {
scope.$$postDigest(function () {
if (isDefined(lastValue)) {
unwatch();
}
});
}
}, objectEquality);
}
But am seeing a pretty word unwatch();inside the function . So i think I need to use $unwatch for the object when end of the $watch function. But I couldn't get anything about $unwatch concept anywhere in angular document. but I can see it on angular script.
I had some idea about manually stop this $watch function by this below way
var unwatch = $scope.$watch("OneTime", function() {
//...
});
setTimeout(function() {
unwatch();
}, 1000);
But I am thinking about if angular provide to unwatch function to stop the abject watching, it would be easy to handle in my whole application. So planed to take override something in angular.js file in my application. let me know if you have any idea about override angular.js script file to create $unwatch function as same as $watch function. And also let me know angular had any$unwatch function.
I think you need one way binding over here
you can achieve this br
{{::oneTime}}
in your html page One-time expressions will stop recalculating once they are stable, which happens after the first digest
var $unwatch=$scope.$watch('onetime',function(){
unregister();
}
AngularJS does already provide such function, exactly as you mentioned above. When you create a watcher, it returns you a function that may be used to stop watching it.
From the $rootScope.Scope documentation,
$watch(watchExpression, listener, [objectEquality]);
Returns: function() Returns a deregistration function for this listener.
The only thing you need to do to unwatch your object would be calling the returned function. You could call it inside your watch function so it will be executed at the first time your watcher is invoked.
var unwatch = null;
// start watching the object
var unwatch = $scope.$watch($scope.OneTime, function(old, new)
{
// my function
if (unwatch != null) {
unwatch();
}
});

Why is $watch not working like I expect - Angular

I am trying to watch a value in my controller. When it changes, I want to send out a broadcast, but I never get inside the $watch function. Here is the function:
$scope.$watch($scope.selectedEncounter, function(selectedEncounter) {
$scope.$broadcast('selecteRowChange', { encounter: selectedEncounter });
});
Can I watch something attached to the scope? If so what is the issue I am having with this code. If not, how do I implement this code to work?
You should pass either a function or a property name to your $watch function.
So, in your case, you should just change your code to:
$scope.$watch('selectedEncounter', function(value) {
// ...
});
Here is some more info from the docs.
The object you are watching is a complex object. Hence you should set objectEquality to true in your code as follows:
$scope.$watch('selectedEncounter', function(selectedEncounter) {
// ....
}, true);
Notice the true value as last parameter to the $scope.$watch function at the end.

$scope.$watch isn't firing after load in angular.js

I'm using angular.js and am trying to use $watch to fire a function when my variable changes. It fires when the data is initially loaded, but not after. I'm not sure exactly what is going on here?
Code is pasted below:
function gradeChart($scope, $http) {
$http.get('studentData.json').success(function(data) {
$scope.students = data;
});
$scope.$watch('students',function(change){
console.log('this fires on load but not after');
});
}
It is not clear what code runs "after" and updates $scope.students.
However, here are the two most common problems related to updating $scope arrays:
If you reassign $scope.students to a new array, the $watch may still be looking at the previous array (reference). Try using angular.copy() in your "after" code:
angular.copy(data, $scope.students);
If you are changing one of the elements of the array, you'll need to use either $watchCollection (if it is available in the version of Angular you are using) or check for object equality instead of reference (note 3rd parameter):
$scope.$watch('students',function(change){...}, true);

Is there a way to watch attribute changes triggered from outside the AngularJS world?

Iā€™m trying to understand interactions between the Angular world and the non-Angular world.
Given a directive that one declares like this:
<dir1 id="d1" attr1="100"/>
If code outside angular changes the directive this way:
$("#d1").attr("attr1", 1000);
How can the directive know that one of its attribute has changed?
It would be best to make this change inside the directive instead. If, for whatever reason, that's not possible, then there are a couple of options.
Outside the app, get a reference to any DOM element within the app. Using that reference, you can then get a reference to its scope. You could use your element with id d1. For example:
var domElement = document.getElementById('d1');
var scope = angular.element(domElement).scope();
Here are a couple of options:
Option 1
Modify the model instead of making a direct change to the view. In the link function, store the initial attribute value in a scope variable like:
scope.myvalue = attrs.attr1;
Then you can change the value outside the app (using the above reference to scope) like:
scope.$apply(function(){
scope.myvalue = 1000;
console.log('attribute changed');
});
Here is a fiddle
Option 2
If the view is manipulated directly with jQuery, I don't know of any use of $observe, $watch, or an isolate scope binding to the attribute that will work, because they all bind to the attribute expression itself, just once, when the link function is first run. Changing the value will cause those bindings to fail. So you'd have to $watch the attribute on the DOM element itself (rather than through attrs):
scope.$watch(function(){
return $(el).attr('attr1'); // Set a watch on the actual DOM value
}, function(newVal){
scope.message = newVal;
});
Then you can change the value outside the app (using the above reference to scope) like:
scope.$apply(function(){
$("#d1").attr("attr1",1000);
});
Here is a fiddle
Use a Web Components library like x-tags by Mozilla or Polymer by Google. This option works without maunally calling $scope.$apply every time the attribute changes.
I use x-tags because of their wider browser support. While defining a new custom tag (directive) you can set the option lifecycle.attributeChanged to a callback function, which will fire every time an argument is changed.
The official docs aren't very helpful. But by trial and error and diving into the code I managed to find out how it works.
The callback function's context (the this object) is the element itself. The one whose attribute has changed. The callback can take three arguments:
name ā€“ the name of the attribute,
oldValue and
newValue ā€“ these speak for themselves.
So now, down to business:
The code
This will watch the attribute for changes:
xtag.register('dir1', {
lifecycle: {
attributeChanged: function (attribute, changedFrom, changedTo) {
// Find the element's scope
var scope = angular.element(this).scope();
// Update the scope if our attribute has changed
scope.$apply(function () {
if (attribute == 'attr1') scope.style = changedTo;
});
}
}
});
The attributeChanged callback only fires when the arguments' values actually change. To get their initial values you need to scan the lot manually. The easiest way seems to be while defining the directive:
myApp.directive('dir1', function () {
return {
... ,
link: function (scope, element, attributes) {
scope.attr1 = element[0].getAttribute('attr1');
}
};
});

Categories

Resources