![]()
What You’ll Learn
What $watch and $watchCollection do
Key differences between them
When to use each one efficiently
Performance optimization tips
1️⃣ Understanding $watch in AngularJS
What is $watch?
$watchmonitors a scope variable and runs a function when its value changes.- It can track primitive values, objects, and arrays.
Syntax
$scope.$watch('variableName', function(newValue, oldValue) {
console.log('Value changed:', oldValue, '➡', newValue);
});
Example: Watching a Primitive Value
$scope.name = "Narendra";
$scope.$watch('name', function(newVal, oldVal) {
console.log("Name changed from", oldVal, "to", newVal);
});
Efficient for simple values like string, number, or boolean.
Watching an Object (Deep Watch)
By default, $watch does not track object properties deeply.
To watch an entire object, pass true as the third argument.
$scope.user = { name: "Narendra", age: 25 };
$scope.$watch('user', function(newVal, oldVal) {
console.log("User changed:", newVal);
}, true); // Deep watch
Deep watch (true) makes performance slower. Use it only when necessary.
2️⃣ Understanding $watchCollection
What is $watchCollection?
$watchCollectionis optimized for arrays and objects.- It tracks changes to top-level properties but does not deep-watch nested properties.
Syntax
$scope.$watchCollection('arrayOrObject', function(newVal, oldVal) {
console.log("Collection changed:", newVal);
});
Example: Watching an Array Efficiently
$scope.items = ["Apple", "Banana", "Cherry"];
$scope.$watchCollection('items', function(newVal, oldVal) {
console.log("Array updated:", newVal);
});
Optimized for tracking additions/removals in arrays.
Problem with $watch for arrays:
$scope.$watch('items', function(newVal, oldVal) {
console.log("Array updated:", newVal);
}, true); // Deep watch (expensive)
Optimized alternative:
$scope.$watchCollection('items', function(newVal, oldVal) {
console.log("Array changed:", newVal);
});
$watchCollection detects new elements, removed elements, or reference changes, but not deep changes inside objects within the array.
3️⃣ Key Differences Between $watch and $watchCollection
| Feature | $watch | $watchCollection |
|---|---|---|
| Tracks primitive values | Yes | Yes |
| Tracks entire objects | (With true) | (Only top-level properties) |
| Detects nested changes | (With deep watch) | No |
| Works well with arrays | No (Expensive deep watch needed) | Yes (Efficient) |
| Best for simple values | Yes | Yes |
| Best for arrays & collections | No | Yes |
4️⃣ When to Use $watch vs $watchCollection?
Use $watch when… | Use $watchCollection when… |
|---|---|
Watching a primitive value (string, number, boolean). | Tracking array length changes (adding/removing items). |
Watching an entire object deeply (if you use true). | Watching objects without deep tracking. |
Tracking nested property changes (user.address.city). | Tracking top-level object property changes. |
5️⃣ Performance Optimization Tips
1. Avoid Deep Watches When Possible
- Deep watches (
true) are expensive and slow down performance. - Instead, watch only the required properties.
Bad (Deep Watch on Large Object):
$scope.$watch('user', function(newVal, oldVal) {
console.log("User updated");
}, true); // Deep watch (slow)
Optimized (Watch Only Required Property):
$scope.$watch('user.name', function(newVal, oldVal) {
console.log("User name updated");
});
Reduces unnecessary digest cycle runs.
2. Use $watchCollection for Arrays Instead of Deep Watching
Good:
$scope.$watchCollection('items', function(newVal, oldVal) {
console.log("Array updated:", newVal);
});
Bad (Expensive Deep Watch on Array):
$scope.$watch('items', function(newVal, oldVal) {
console.log("Array updated");
}, true); // Deep watch (slow)
$watchCollection is faster for tracking array additions/removals.
3. Use One-Time Binding (::) for Static Data
If a value never changes, use one-time binding in templates to remove watchers.
<h1>{{ ::title }}</h1> <!-- Only evaluated once -->
Removes unnecessary watchers, improving performance.
4. Use $timeout() Instead of $apply() to Prevent Extra Digest Cycles
When updating scope asynchronously, avoid $apply() as it triggers a full digest cycle.
Bad:
setTimeout(function () {
$scope.message = "Updated";
$scope.$apply(); // Forces a full digest cycle
}, 1000);
Optimized:
$timeout(function () {
$scope.message = "Updated"; // Triggers digest automatically
}, 1000);
$timeout() schedules updates without forcing an extra digest cycle.
6️⃣ Final Summary
| Aspect | $watch | $watchCollection |
|---|---|---|
| Best for | Primitives, individual properties | Arrays, object top-level properties |
| Tracks deep changes? | Yes (with true) | No |
| Performance impact | Higher (with deep watch) | Lower |
| Replaces deep watch for arrays? | No | Yes |
Alternative to $watch(true)? | No | Yes |
