$rootScope.Scope.$watch()

$watch(watchExpression, listener, [objectEquality]);

Registers a listener callback to be executed whenever the watchExpression changes.

  • The watchExpression is called on every call to $digest() and should return the value that will be watched. (watchExpression should not change its value when executed multiple times with the same input because it may be executed multiple times by $digest(). That is, watchExpression should be idempotent.
  • The listener is called only when the value from the current watchExpression and the previous call to watchExpression are not equal (with the exception of the initial run, see below). Inequality is determined according to reference inequality, strict comparison via the !== Javascript operator, unless objectEquality == true (see next point)
  • When objectEquality == true, inequality of the watchExpression is determined according to the angular.equals function. To save the value of the object for later comparison, the angular.copy function is used. This therefore means that watching complex objects will have adverse memory and performance implications.
  • The watch listener may change the model, which may trigger other listeners to fire. This is achieved by rerunning the watchers until no changes are detected. The rerun iteration limit is 10 to prevent an infinite loop deadlock.

If you want to be notified whenever $digest is called, you can register a watchExpression function with no listener. (Be prepared for multiple calls to your watchExpression because it will execute multiple times in a single $digest cycle if a change is detected.)

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.

// let's assume that scope was dependency injected as the $rootScope
var scope = $rootScope;
scope.name = 'misko';
scope.counter = 0;

expect(scope.counter).toEqual(0);
scope.$watch('name', function(newValue, oldValue) {
  scope.counter = scope.counter + 1;
});
expect(scope.counter).toEqual(0);

scope.$digest();
// the listener is always called during the first $digest loop after it was registered
expect(scope.counter).toEqual(1);

scope.$digest();
// but now it will not be called unless the value changes
expect(scope.counter).toEqual(1);

scope.name = 'adam';
scope.$digest();
expect(scope.counter).toEqual(2);



// Using a function as a watchExpression
var food;
scope.foodCounter = 0;
expect(scope.foodCounter).toEqual(0);
scope.$watch(
  // This function returns the value being watched. It is called for each turn of the $digest loop
  function() { return food; },
  // This is the change listener, called when the value returned from the above function changes
  function(newValue, oldValue) {
    if ( newValue !== oldValue ) {
      // Only increment the counter if the value changed
      scope.foodCounter = scope.foodCounter + 1;
    }
  }
);
// No digest has been run so the counter will be zero
expect(scope.foodCounter).toEqual(0);

// Run the digest but since food has not changed count will still be zero
scope.$digest();
expect(scope.foodCounter).toEqual(0);

// Update food and run digest.  Now the counter will increment
food = 'cheeseburger';
scope.$digest();
expect(scope.foodCounter).toEqual(1);

Parameters

Param Type Details
watchExpression function()string

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.
listener function(newVal, oldVal, scope)

Callback called whenever the value of watchExpression changes.

  • newVal contains the current value of the watchExpression
  • oldVal contains the previous value of the watchExpression
  • scope refers to the current scope
objectEquality
(optional)
boolean

Compare for object equality using angular.equals instead of comparing for reference equality.

(default: false)

Returns

function()

Returns a deregistration function for this listener.

doc_AngularJS
2016-03-29 16:10:40
Comments
Leave a Comment

Please login to continue.