What is considered a watcher in Angular?

What are considered "watchers" in Angular? Are watchers themselves the only type of watchers, or are other Angular constructs such as ngModel watchers as well?

Or am I missing the big picture? For example, are watchers what enable directives like ngModel to work?

update: Is there a way to tell when there exists watchers? In testing I want to know when to call scope.$digest()


ANSWERS:


watchers is nothing but dirty checking, which keeps a track of the old value and new value

They are getting evaluated on each digest cycle. It can be combination of scope variable or any expression. Angular does collect all of this watchers on each digest cycle and mainatain it inside $$watchers array. you could look at how many watchers are there by doing console.log($scope.$watchers) inside your controller.

Markup

<body class="container" ng-controller="myCtrl">
  Hello {{test}}
  I'm test to show $$watchers {{test1}}
  <div ng-show="show">SHowiing this div using ng-show</div>
  <div ng-if="show">SHowiing this div using ng-show</div>
  Watcher is not compulsary that should scope variables {{'1'}}
</body>

Plunkr

Guess in above code how many watchers are there, as you can see there are 3 {{}} interpolation directive that are going to place in watchers array and then if you see in console $scope.$$watchers it will show 5 watchers.

How come there it shows 5 watchers. As we can only see 3, Actually we've used ng-show and ng-if directive which internally place $watch on the expression provided in its attribute value. & those expression gets evaluated on each digest cycle.

You could also create your custom watcher by using $watch(deep/simple watch) & $watchGroup

Also you could have watcher use $attrs.$observe, this does work same as the watch but the only special thing it does it, it works for the interpolation variable.

$attrs.$observe('test',function(value){
    alert('')
});

Most of angular directive internally uses watcher like ng-repeat, ng-show, ng-if, ng-include, ng-switch, ng-bind,interpolation directive {{}}, filters, etc. They put watch internally to manage two way binding thing.


Watchers (if we take only the documentation you are based on) are angular mechanisms aiming to observe in a two-way binding style a variable or a function result during any Angular digest cycle; and no matter what the triggering event of the digest cycle would be.

I would call a "watcher" any Angular mechanism that are able to trigger some codes based on ANY event that could occur.

Typically, to create a Watcher, you should use: $scope.watch(...)

Just be aware that it's better to avoid watchers as long as we can.
Indeed, their callback would be triggered at EACH digest cycle to perform dirty checking; often impacting performance.

ng-model is not linked with the concept of watcher.
ng-model is just a way to bind some variable from view to controller.
They are two distinct concepts.


To illustrate how $watch(), $digest() and $apply() works, look at this example:

<div ng-controller="myController">
{{data.time}}

<br/>
<button ng-click="updateTime()">update time - ng-click</button>
<button id="updateTimeButton"  >update time</button>
</div>
<script>
var module = angular.module("myapp", []);
var myController1 = module.controller("myController", function($scope) {
    $scope.data = { time : new Date() };
    $scope.updateTime = function() {
        $scope.data.time = new Date();
    }
    document.getElementById("updateTimeButton")
            .addEventListener('click', function() {
        console.log("update time clicked");
        $scope.data.time = new Date();
    });
});
</script>

This example binds the $scope.data.time variable to an interpolation directive which merges the variable value into the HTML page. This binding creates a watch internally on the $scope.data.time variable.

The example also contains two buttons. The first button has an ng-click listener attached to it. When that button is clicked the $scope.updateTime() function is called, and after that AngularJS calls $scope.$digest() so that data bindings are updated.

The second button gets a standard JavaScript event listener attached to it from inside the controller function. When the second button is clicked that listener function is executed. As you can see, the listener functions for both buttons do almost the same, but when the second button's listener function is called, the data binding is not updated. That is because the $scope.$digest() is not called after the second button's event listener is executed. Thus, if you click the second button the time is updated in the $scope.data.time variable, but the new time is never displayed.

To fix that we can add a $scope.$digest() call to the last line of the button event listener, like this:

document.getElementById("updateTimeButton")
    .addEventListener('click', function() {
console.log("update time clicked");
$scope.data.time = new Date();
$scope.$digest();
});

Instead of calling $digest() inside the button listener function you could also have used the $apply() function like this:

document.getElementById("updateTimeButton")
    .addEventListener('click', function() {
$scope.$apply(function() {
    console.log("update time clicked");
    $scope.data.time = new Date();
});
});

Notice how the $scope.$apply() function is called from inside the button event listener, and how the update of the $scope.data.time variable is performed inside the function passed as parameter to the $apply() function. When the $apply() function call finishes AngularJS calls $digest() internally, so all data bindings are updated.



 MORE:


 ? AngularJS is cross-binding variables?
 ? AngularJS – Subtract two-way bind from one-time bind
 ? Navigate on AngularJS + Kendo UI Mobile
 ? Angular directive is not detecting change in parent controller's properties
 ? Why isn't my view updating when changing the model of different directive scopes but bounded (what appears to be) correctly?
 ? Removing element from DOM via ng-if bound to attribute directive scope property
 ? Angular Components: What is the difference between one-way and attribute bindings?
 ? Angular Components: What is the difference between one-way and attribute bindings?
 ? Angular Components: What is the difference between one-way and attribute bindings?
 ? Proper way to wait Angular Component bindings stabilize before doing initializations on the child scopes?