Angular JS Magazine

vineri, 9 ianuarie 2015

Angular JS - Use $watch For Watching Multiple Things

In this tip, you can see three use cases for $watch:
  •  use $watch for watching all properties of an object
  •  use $watch for watching only some properties of the same object
  •  use $watch for watching only some properties for different objects
Per example, when you calculate the PS Eden Space for memory pools (current utilization), you need the used MB, committed MB and max available MB. You can easily group these info under a object, like this sample:

$scope.mp = { usedmb: 72, committedmb: 139, maxmb: 140 };

Now, the current utilization is computed in a function, like this:

$scope.computePSEdenSpace = function () {
    $scope.pses = ($scope.mp.usedmb * 100.0)/($scope.mp.maxmb);
}

If you let the user to provide these three info via input texts then you may need to watch the entire $scope.mp for changes, like this:

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script src="../angular/angular.min.js"></script>
<link href="../bootstrap/css/bootstrap.css" rel="stylesheet"/>
<link href="../bootstrap/css/bootstrap-theme.css" rel="stylesheet"/>
 <script>
   angular.module("myModule", [])
            .controller("myCtrl", function ($scope) {
                  
            $scope.pses = 0.0;
            $scope.mp = { usedmb: 72, committedmb: 139, maxmb: 140 };

            $scope.computePSEdenSpace = function () {
              $scope.pses = ($scope.mp.usedmb * 100.0)/($scope.mp.maxmb);
            }

            $scope.$watch('mp', 'computePSEdenSpace()', true);
  });
  </script>
 </head>
<body>
<div ng-app="myModule">

    <div id="myPanel" class="panel" ng-controller="myCtrl">
    <h4 class="panel-header">$watch - Watching multiple things</h4>
    <hr/>
    <table>
      <tr>
       <td>Used (MB):</td>
       <td><input class="form-control" ng-model="mp.usedmb"></td>
      </tr>
      <tr>
       <td>Comitted (MB):</td>
       <td><input class="form-control" ng-model="mp.committedmb"></td>
      </tr>
      <tr>
       <td>Max Available (MB):</td>
       <td><input class="form-control" ng-model="mp.maxmb"></td>
      </tr>
   </table>
   <br/>
   <span class='label label-primary'>PS Eden Space:</span> 
   <strong>{{pses | number:1}}</strong>%
 </div>
</div>
</body>
</html>

This worked ok, but if you take a closer look to the formula nested in the $scope.computePSEdenSpace() function you will notice that it depends on used MB and max available MB, and is independent of comitted MB. Since we are watching the entire $scope.mp, this function is called when the user modify the committed MB also, which is useless. We can fix this by replacing the:

  $scope.$watch('mp', 'computePSEdenSpace()', true);

with the below concatenation:

$scope.$watch('mp.usedmb + mp.maxmb', 'computePSEdenSpace()');

Now, we watch only these two properties of the  $scope.mp object, and the $scope.computePSEdenSpace() function is not called anymore when the user modify the committed MB.

Note: Based on this example, you can even watch properties from different objects, by simply concatenating the corresponding properites!!!