Using $watch vs $watchCollection efficiently

Loading

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?

  • $watch monitors 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?

  • $watchCollection is 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 forPrimitives, individual propertiesArrays, object top-level properties
Tracks deep changes?Yes (with true)No
Performance impactHigher (with deep watch)Lower
Replaces deep watch for arrays?NoYes
Alternative to $watch(true)?NoYes

Leave a Reply

Your email address will not be published. Required fields are marked *