Home > Web Front-end > JS Tutorial > Mastering $watch in AngularJS

Mastering $watch in AngularJS

Lisa Kudrow
Release: 2025-02-18 10:47:09
Original
729 people have browsed it

Mastering $watch in AngularJS

Core points

  • The $watch function in AngularJS is a powerful tool for observing changes in variable values ​​or expressions. When a change is detected, it triggers a callback function that is executed every time the monitored variable changes.
  • $watch Use JavaScript's equality operator (===) for comparison. If the new value is different from the old value, the callback function is triggered. However, it should be noted that by default, $watch only checks for reference equality, which means that the callback function is triggered only when a new value is assigned to the monitored variable.
  • AngularJS also provides $watchGroup and $watchCollection as convenient shortcuts for setting up multiple monitors or monitoring arrays or objects with the same callback function, respectively. However, these methods only perform shallow monitoring and react only to reference changes.
  • Using $watch, especially on multiple variables, may affect performance because changes in all monitored variables need to be checked for each summary cycle. Developers should consider using $watchGroup or $watchCollection depending on the situation, or limit the number of monitored variables to improve performance.

This article was reviewed by Mark Brown. Thanks to all the peer reviewers of SitePoint for getting SitePoint content to its best!

AngularJS offers many different options to use the publish-subscribe mode through three different "watch" methods. Each method takes optional parameters to modify its behavior.

The official documentation about $watch is far from exhaustive: after all, this is a problem that bothers AngularJS v1 as a whole. Even online resources that explain how to proceed are fragmented at best.

So, ultimately, it is difficult for developers to choose the right approach for a particular situation. This is especially true for beginners in AngularJS! The results can be surprising or unpredictable, which inevitably leads to errors.

In this article, I will assume that you are familiar with the AngularJS concept. If you feel you need to review, you may need to read about $scope, bindings, and $apply and $digest.

Check your understanding

For example, what is the best way to monitor the first element of an array? Suppose we declare an array on our scope, $scope.letters = ['A','B','C'];

  • When we add elements to an array, will $scope.$watch('letters', function () {...}); trigger its callback function?
  • When we change its first element, will it fire?
  • Where is
  • $scope.$watch('letters[0]', function () {...});? Will it work the same way, or is it better?
  • Above, the array element is the original value: What if we replace the first element with the same value?
  • Now assume that the array contains objects: What happens?
  • What is the difference between
  • $watch, $watchCollection and $watchGroup?

If you are confused by all these questions, please continue reading. My goal is to walk you through the process by explaining this as clearly as possible with a few examples.

$scope.$watch

Let's start with $scope.$watch. Here is the core of all watch features: every other method we will see is just a convenient shortcut to $watch.

Using$watch

The advantage of Angular is that you can explicitly use the same mechanism to perform complex operations triggered by data changes in the controller. For example, you can set up a monitor for certain data that can be changed in response to:

  1. Timeout
  2. UI
  3. Complex asynchronous calculations performed by Web Worker
  4. Ajax call

You can set up just one listener to handle any data changes, no matter what the cause is.

However, to do this, you need to call $scope.$watch yourself.

Practical Operation

Let's look at the code of $rootscope.watch().

This is its signature: function(watchExp, listener, objectEquality, prettyPrintExpression).

In detail, its four parameters:

  1. watchExp Monitored expression. It can be a function or a string, and it is evaluated in every digest cycle.

    A key aspect to note here is that If the expression is evaluated as a function, the function needs to be idempotent. In other words, for the same input set it should always return the same output. If this is not the case, Angular will assume that the monitored data has been changed. This in turn means it will continue to detect differences and call the listener in each iteration of the digest cycle.

  2. listener A callback function that is fired when the monitor is first set up, and then every time a change in the watchExp value is detected during the summary cycle. The initial call at setting is intended to store the initial value for the expression.

  3. objectEquality The monitor will perform a depth comparison if and only if this value is true. Otherwise, it performs shallow comparisons, i.e. only comparison references.

    Let's take array as an example: $scope.fruit = ["banana", "apple"];

    objectEquality == false means that only the reassignment of the fruit field will cause the listener to be called.

    We also need to check how deep the “deep” is: we will discuss this later.

  4. prettyPrintExpression If passed, it will override the monitoring expression. This parameter is not intended to be used in normal calls to $watch(); it is used internally by the expression parser.

    Beware: As you can see yourself, unexpected results are prone to unexpected results when the fourth parameter is passed accidentally.

Now we are going to answer some of the questions in the introduction. Please check out the examples of this section:

CodePen example

Feel free to familiarize yourself with them; you can directly compare behavior differences, or do it in the order in the article.

Monitoring Array

So you need to monitor the array on the scope to make changes, but what does "change" mean?

Suppose your controller looks like this:

app.controller('watchDemoCtrl', ['$scope', function($scope){
    $scope.letters = ['A','B','C'];
}]);
Copy after login
Copy after login
Copy after login

One option is to use a call like this:

$scope.$watch('letters', function (newValue, oldValue, scope) {
    // 对 $scope.letters 执行任何操作
});
Copy after login
Copy after login
Copy after login

In the above callback, newValue and oldValue have self-explanatory meanings and are updated every time the $digest cycle calls it. The meaning of scope is also intuitive, because it holds references to the current scope.

But the key is: When will this listener be called? In fact, you can add, delete, replace elements in an array without anything happening. This is because, by default, letters assumes that you only want $watch reference equality, so the callback function is triggered only when you assign a new value to . $scope.letters

If you need to take action on changes to any element of the array, you need to pass

as the third parameter to true (i.e. as the value of the optional watch parameter described above). objectEquality

$scope.$watch('letters', function (newValue, oldValue, scope) {
    // 对 $scope.letters 执行任何操作
}, true);
Copy after login
Copy after login
Surveillance object

For objects, the situation does not change: if

is false, you just monitor any reassignment to that scope variable, and if true, the callback function will be triggered every time the element in the object is changed. objectEquality

The first element of the monitoring array

It is worth noting that by monitoring the array using

, each time the callback function is triggered, objectEquality === true and newValue will be the old and new values ​​of the entire array. So you have to compare them with each other to understand what actually changes. oldValue

Suppose you are only interested in changes to the first element (or the fourth element-the same principle) in the array. Since Angular is excellent, it allows you to do this: You can express it in a natural way in the expression passed to

as the first argument: $watch

$scope.$watch('letters[4]', function (newValue, oldValue, scope) {
    //...
}, true);
Copy after login
Copy after login
What happens if the array has only 2 elements? No problem, your callback function won't be fired unless you add a fourth element. OK OK, technically it fires when you set up the monitor and then only when you add the fourth element.

If you record oldValue, you will see that in both cases it will be undefined. Compare this to what happens when monitoring existing elements: When set up, you still have oldValue == undefined. So $watch cannot be processed!

A more interesting question now: Do we need to pass objectEquality === true here?

Short answer: Sorry, there is no short answer.

It really depends on:

  • In this example, since we are working on the original value, we do not need depth comparisons, so we can omit objectEquality.
  • But, suppose we have a matrix, for example $scope.board = [[1, 2, 3], [4, 5, 6]]; and we want to monitor the first row. Then we might want to get an alert when an assignment like $scope.board[0][1] = 7 changes it.

Fields of monitoring objects

Perhaps more useful than monitoring any element in an array, we can monitor any field in an object. But that's not surprising, right? After all, an array in JavaScript is a object.

app.controller('watchDemoCtrl', ['$scope', function($scope){
    $scope.letters = ['A','B','C'];
}]);
Copy after login
Copy after login
Copy after login

How deep is the depth?

At this point, we also need to clarify one last but crucial detail: What happens if we need to monitor a complex nested object where each field is a non-primitive value? For example, a tree or graph, or just some JSON data.

Let's check it out!

First of all, we need an object to monitor:

$scope.$watch('letters', function (newValue, oldValue, scope) {
    // 对 $scope.letters 执行任何操作
});
Copy after login
Copy after login
Copy after login

Let's set up the monitor for the entire object: I think so far it's clear that in this case objectEquality must be set to true.

$scope.$watch('letters', function (newValue, oldValue, scope) {
    // 对 $scope.letters 执行任何操作
}, true);
Copy after login
Copy after login

The question is: if assignments like $scope.b.bb[1].bb2a = 7; happen, will Angular be kind enough to let us know?

The answer is: Yes, luckily, it will (see in the previous CodePen demo).

Other methods

$scope.$watchGroup

$watchGroup()Is it really a different approach? The answer is no, it is not.

$watchGroup() is a convenient shortcut that allows you to set up multiple monitors using the same callback function and pass an array of watchExpressions.

Each passed expression will be monitored using the standard $scope.$watch() method.

$scope.$watch('letters[4]', function (newValue, oldValue, scope) {
    //...
}, true);
Copy after login
Copy after login

It is worth noting that using $watchGroup, newValues and oldValues will save the list of values ​​of the expression, including the values ​​that have changed and those that have kept the same value, in the order of them in the first parameter The order of passing in the array is the same.

If you checked the documentation for this method, you may notice that it does not take the objectEquality option. This is because it shallowly monitors expressions and only reacts to reference changes.

If you use the $watchGroup() demo below, you may be surprised by some subtleties. For example, unshift will cause the listener to be called, at least to some extent: This is because when passing the expression list to $watchGroup, any triggers an expression that will result in execution Callback function.

CodePen example

Also, note that any changes to any subfield of

will not produce any updates - updates will only be generated if a new value is assigned to the b field itself. $scope.obj.b

$scope.$watchCollection

This is another convenient shortcut to monitor arrays or objects. For arrays, the listener is called when any element is replaced, deleted, or added. For objects, when any properties are changed. Again,

does not allow $watchCollection(), so it only shallowly monitor elements/fields and does not react to changes in their subfields. objectEquality

CodePen example

Conclusion

Hope these examples help you discover the power of this Angular feature and understand how important it is to use the right options.

Feel free to copy CodePen and try to use these methods in different contexts and don't forget to leave your feedback in the comments section!

If you want to have a deeper look at some of the concepts we discussed in this article, here are some suggestions for further reading:

    AngularJS scope
  1. Understand Angular's
  2. and $apply()$digest()
  3. Emerging Patterns in JavaScript Event Processing
  4. Prototype inheritance in AngularJS scope
  5. Documents of
  6. etc.$watch

FAQs (FAQ)$watch in AngularJS

$watchWhat is the main purpose in AngularJS?

The $watch function in AngularJS is mainly used to observe changes in the value of a variable or expression. It is part of AngularJS scoped object to monitor changes in the value of a variable or expression. When a change is detected, the $watch function triggers a callback function that is executed every time the monitored variable changes.

$watchHow does it work in AngularJS?

The $watch function in AngularJS works by comparing the old and new values ​​of the monitored variable or expression. It uses JavaScript's equality operator (===) for comparison. If the new value is different from the old value, the $watch function will trigger the callback function.

How do I use $watch in AngularJS?

To use $watch in AngularJS, you need to call the $watch method on the scope object and pass it two parameters: the name of the variable or expression to be monitored, and happens when the variable being monitored The callback function to be executed when changing. Here is an example:

app.controller('watchDemoCtrl', ['$scope', function($scope){
    $scope.letters = ['A','B','C'];
}]);
Copy after login
Copy after login
Copy after login
What is the difference between

$watch and $apply in AngularJS?

The

function in $watch in AngularJS is used to observe changes in variables or expressions, while the $apply function is used to manually start the AngularJS digest period, which checks for any changes in the monitored variable and updates the view accordingly. The $apply function is usually used when making model changes outside the AngularJS context, such as in the DOM event handler or the setTimeout function.

Can I monitor multiple variables in AngularJS using $watch?

Yes, you can use $watch to monitor multiple variables in AngularJS. You can do this by passing an array of variable names to the $watch function. However, remember that monitoring multiple variables can affect performance, because the $watch function needs to check for changes in all monitored variables in each digest cycle.

How do I stop monitoring variables in $watch in AngularJS?

When you call the $watch function in AngularJS, it returns a logout function. You can call this function to stop monitoring variables. Here is an example:

$scope.$watch('letters', function (newValue, oldValue, scope) {
    // 对 $scope.letters 执行任何操作
});
Copy after login
Copy after login
Copy after login

What is $watchGroup in AngularJS?

The $watchGroup function in AngularJS is used to monitor a set of expressions. It works like the $watch function, but it triggers the callback function only once per digest cycle, even if multiple monitored expressions change. This can improve performance when monitoring multiple expressions.

What is $watchCollection in AngularJS?

The $watchCollection function in AngularJS is used to monitor the attributes of an object or elements of an array. It triggers the callback function as long as any attribute or element changes, but unlike $watch, it does not deeply monitor objects or arrays, which can improve performance.

Can I use $watch in AngularJS directive?

Yes, you can use $watch in the AngularJS directive. In fact, it is common to use $watch in directives to respond to changes in attributes or scope variables of directives.

What are the performance considerations in AngularJS using $watch?

Using $watch in AngularJS can affect performance, especially when monitoring many variables or expressions. This is because the $watch function needs to check the changes of all monitored variables in each digest cycle. To improve performance, consider using $watchGroup or $watchCollection according to the situation, or limit the number of monitored variables.

The above is the detailed content of Mastering $watch in AngularJS. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template