Chapter 7: Creating a universal watch callback
HTML
<script src="https://code.angularjs.org/1.3.2/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="Ctrl">
<input ng-model="foo" />
<input ng-model="bar" />
<div>{{ foo }}</div>
<div>{{ bar }}</div>
<button ng-click="logWatchers()">Log Watchers</button>
</div>
</div>
JavaScript
angular.module('myApp', [])
.controller('Ctrl', function ($scope, $log) {
// invoked once every time $scope.foo is modified
$scope.$watch('foo', function (newVal, oldVal, scope) {
// newVal is the current value of $scope.foo
// oldVal isa the previous value of $scope.foo
// scope === $scope
});
// invoked once every time $scope.bar is modified
$scope.$watch('bar', function (newVal, oldVal, scope) {
// newVal is the current value of $scope.bar
// oldVal is the previous value of $scope.bar
// scope === $scope
});
// invoked once every $digest cycle
$scope.$watch(function (scope) {
// scope === $scope
});
$scope.logWatchers = function() {
$log.log(getWatchers());
};
});
var getWatchers = function (element) {
// convert to a jqLite/jQuery element
// angular.element is idempotent
var el = angular.element(
// defaults to the body element
element || document.getElementsByTagName('body')
)
// extract the DOM element data
, elData = el.data()
// initalize returned watchers array
, watchers = [];
// AngularJS lists watches in 3 categories
// each contains an independent watch list
angular.forEach([
// general inherited scope
elData.$scope,
// isolate scope attached to templated directive
elData.$isolateScope,
// isolate scope attached to templateless directive
elData.$isolateScopeNoTemplate
],
function (scope) {
// each element may not have a scope class attached
if (scope) {
// attach the watch list
watchers = watchers.concat(scope.$$watchers || []);
}
}
);
document.body.gw = 'getWatchers';
// recurse through DOM tree
angular.forEach(el.children(), function (childEl) {
watchers =...