Is only one $watch created regardless of how many DOM elements are bound to the watched $scope?

StackOverflow https://stackoverflow.com/questions/23617347

  •  21-07-2023
  •  | 
  •  

Вопрос

In the following code, is there only one $watch created even though the <input> element and interpolation of the double curlies {{customer.name}} create two different bindings to $scope.customer.name?

<html ng-app>
   <body>
     <input ng-model="customer.name" />
     {{customer.name}}
     <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular.min.js"></script>
  </body>
</html>

As a follow-up, does the resulting callback to the listener defined in the $watch update the DOM and re-render those changed elements?

Это было полезно?

Решение

Answer to question 1:

There will be two watchers added.

Slightly simplified, a watcher is an object that is added to the scopes $$watchers array. This watcher object has a watchFunction and a listenerFunction.

Even if you used $watch to register the same pair of watch- and listenerFunction twice, there would be two watcher objects added.

Answer to question 2:

It depends on the watcher.

Consider the interpolation in your example: {{ customer.name }}

The listenerFunction (the function that is executed when the watched expression has changed) of the associated watch object will look like this:

function interpolateFnWatchAction(value) {
  node[0].nodeValue = value;
}

Pretty straightforward. The listenerFunction will update the node's nodeValue with the new value. When Angular's digest loop is finished the execution leaves Angular and the JavaScript context, which is followed by the browser re-rendering the DOM to reflect changes. Again a bit simplified.

When it comes to the ng-model directive, it gets more complex, since it has a two-way data binding ($scope --> view and view --> $scope) while the previous case has a one-way data binding ($scope --> view).

The watcher added from ng-model doesn't even register a listenerFunction. Instead it performs work in the watchFunction.

I will not go deeper into the matter, but might as well put the code below (which can be found here):

$scope.$watch(function ngModelWatch() {
  var value = ngModelGet($scope);

  // if scope model value and ngModel value are out of sync
  if (ctrl.$modelValue !== value) {

    var formatters = ctrl.$formatters,
      idx = formatters.length;

    ctrl.$modelValue = value;
    while (idx--) {
      value = formatters[idx](value);
    }

    if (ctrl.$viewValue !== value) {
      ctrl.$viewValue = ctrl.$$lastCommittedViewValue = value;
      ctrl.$render();
    }
  }

  return value;
});

Другие советы

Every ng-* and angular expression create internally a separate watcher. If you want to check how many watchers are created you could check for angular private scope property scope.$$watchers

Sometimes there could be a lot of this watchers for a complex app, with some performance issue, that's why library as Bindonce was born (in the demo you could find interesting code to check watchers)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top