<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
<script src="script.js"></script>
<meta charset="utf-8" />
<title>
Scope $watch() vs. $watchCollection() In AngularJS
</title>
<style type="text/css">
h1, h2 {
font-size: 16px;
}
a[ ng-click ] {
cursor: pointer ;
text-decoration: underline ;
}
</style>
</head>
<body ng-app="Demo" ng-controller="AppController">
<h1>
Scope $watch() vs. $watchCollection() In AngularJS
</h1>
<p>
<a ng-click="changeDeepValue()">Change Value on Property (Element) in Collection</a>
—<br>
<a ng-click="changeShallowValue()">Add Property (Element) to Collection</a>
—<br>
<a ng-click="rebuild()">Rebuild</a>
—
<a ng-click="empty()">Empty Collection</a>
—
<a ng-click="clear()">Clear Log</a>
<h2>
$watch( collection ) Log
</h2>
Normal watch is only triggered if the value changes. E.g. an
array is still an array to it, regardless how many elements are in it.
<ul>
<li ng-repeat="item in watchLog">
{{ item }}
</li>
</ul>
<h2>
$watch( collection, [ Equality = true ] ) Log
</h2>
equality = true, or deep watch checks also if any property inside
the collection has changed, i.e it will trigger if an element
is added, or if an element has a changed value. This can become
very expensive.
<ul>
<li ng-repeat="item in watchEqualityLog">
{{ item }}
</li>
</ul>
<h2>
$watchCollection( collection ) Log
</h2>
watchCollection shallow watches the content of an collection.
It is only triggered if an element is added, removed or moved.
<ul>
<li ng-repeat="item in watchCollectionLog">
{{ item }}
</li>
</ul>
</body>
</html>
// Code goes here
// Create an application module for our demo.
var app = angular.module( "Demo", [] );
// -------------------------------------------------- //
// -------------------------------------------------- //
// I control the root of the application.
app.controller(
"AppController",
function( $scope ) {
// These are the log item to render upon change.
$scope.watchCollectionLog = [];
$scope.watchLog = [];
$scope.watchEqualityLog = [];
// I am the collection being watched.
$scope.collection = [
{
id: 1,
value: 0
}
];
// Use the relatively new watchCollection().
$scope.$watchCollection(
"collection",
function( newValue, oldValue ) {
addLogItem( $scope.watchCollectionLog );
}
);
// Use the old watch() with default object equality,
// which defaults to use object REFERENCE checks.
$scope.$watch(
"collection",
function( newValue, oldValue ) {
addLogItem( $scope.watchLog );
}
);
// Use the old watch() method, but turn on deep object
// equality, which will compare the deep object tree
// for changes.
$scope.$watch(
"collection",
function( newValue, oldValue ) {
addLogItem( $scope.watchEqualityLog );
},
true // Object equality (not just reference).
);
// ---
// PUBLIC METHODS.
// ---
// Change a deep value in an existing item on in the
// current collection.
$scope.changeDeepValue = function() {
$scope.collection[ 0 ].value = now();
};
// Add a new item to the collection, causing a change
// in the shallow topology of the collection.
$scope.changeShallowValue = function() {
// Add new item to collection.
$scope.collection.push({
id: ( $scope.collection.length + 1 ),
value: now()
});
};
$scope.empty = function() {
$scope.collection.length = 0;
}
// I clear the log items.
$scope.clear = function() {
$scope.watchCollectionLog = [];
$scope.watchLog = [];
$scope.watchEqualityLog = [];
};
// I rebuild the underlying collection, completely
// changing the reference.
$scope.rebuild = function() {
$scope.collection = [{
id: 1,
value: 0
}];
};
// ---
// PRIVATE METHODS.
// ---
// I add a log item to the beginning of the given log.
function addLogItem( log ) {
var logItem = (
"Executed: " + now() +
" ( length: " + $scope.collection.length + " )"
);
log.splice( 0, 0, logItem );
}
// I return the current UTC milliseconds.
function now() {
return( ( new Date() ).getTime() );
}
}
);
/* Styles go here */