N.F.
N.F.

Reputation: 4202

angularjs : change which variables to watch

I would like to change which variables to watch.

JS:

var app = angular.module('myApp', []);

app.controller('MainController', 
  function($scope) {
    
    $scope.current = null;
    $scope.select = function(item) {
      $scope.current = item;
    };
    
    var watch = ['current'];
    $scope.$watchGroup(watch, function() {                 // This does not work
      if ($scope.current !== null) {
        watch = ['current'];
        Array.prototype.push.apply(watch, $scope.current.watch);
        $scope.current.callBack();
      }  
    });
    
    $scope.list = [
        {
          name: 'test-A',
          watch: ['a'],
          callBack: function() {
            $scope.value = 2 * $scope.a;
          }
        },
        {
          name: 'test-B',
          watch: ['b'],
          callBack: function() {
            $scope.value = 3 * $scope.b;
          }
        }
      ];
  
});

HTML:

<!DOCTYPE html>
<html ng-app="myApp">

<head>
  <link data-require="[email protected]" data-semver="3.3.7" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
  <script data-require="jquery" src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.slim.min.js"></script>
  <script data-require="[email protected]" data-semver="3.3.7" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
  <script data-require="[email protected]" data-semver="1.6.6" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.min.js"></script>
  <link rel="stylesheet" href="style.css" />
  <script src="script.js"></script>
</head>

<body ng-controller="MainController">
  <div class="dropdown">
    <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
      {{current != null ? current.name : 'DropDown'}}
      <span class="caret"></span>
    </button>
    <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
      <li ng-repeat="item in list">
        <a href="javascript:void(0)" ng-click="select(item)">{{item.name}}</a>
      </li>
    </ul>
  </div>
  When "test-A" is selected, result is 2 times of A.
  <br> When "test-B" is selected, result is 3 times of B.

  <br>
  <br>
  <br>

  <form class="form-inline">
    <div class="form-group">
      <label>A</label>
      <input type="text" class="form-control" ng-model="a">
    </div>
    <div class="form-group">
      <label>B</label>
      <input type="text" class="form-control" ng-model="b">
    </div>
  </form>

  <br> result : {{value}}
  <br>
</body>

</html>

This is Plunker example.

The result should be 2 times of A when test-A is selected, should be 3 times of B when test-B is selected.

I would like to update which variables to be watched. But the way shown in the line This does not work does not work. This $watchGroup only fires when current is changed. I would like to fire this $watchGroup when current or a is changed in case test-A is selected, and when current or b is changed in case test-B is selected.

I know $scope.$watchGroup(['a', 'b', 'current'], ... works. But I do not like to fire this $watchGroup when test-A is selected and b is changed and vice versa.

How can I update which variables to be watched?

Upvotes: 0

Views: 69

Answers (2)

I. Ahmed
I. Ahmed

Reputation: 2534

Change the line:

$scope.$watchGroup(watch, function() {

as below:

$scope.$watch('current', function() { 

The reason behind this is the current value is changed when you clicked on menu. var watch = ['current']; is different variable and this one is not changed when you click on menu. To work properly watch, you need to point to the correct variable, in your case, $scope.current is the correct variable.

// Code goes here

var app = angular.module('myApp', []);

app.controller('MainController', 
  function($scope) {
    
    $scope.current = null;
    $scope.select = function(item) {
      $scope.current = item;
    };
    
    var watch = ['current'];
    $scope.$watch('current', function() {
      if ($scope.current !== null) {
        watch = ['current'];
        Array.prototype.push.apply(watch, $scope.current.watch);
        $scope.current.callBack();
      }  
    });
    
    $scope.list = [
        {
          name: 'test-A',
          watch: ['a'],
          callBack: function() {
            $scope.value = 2 * $scope.a;
          }
        },
        {
          name: 'test-B',
          watch: ['b'],
          callBack: function() {
            $scope.value = 3 * $scope.b;
          }
        }
      ];
  
});
<!DOCTYPE html>
<html ng-app="myApp">

<head>
  <link data-require="[email protected]" data-semver="3.3.7" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
  <script data-require="jquery" src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.slim.min.js"></script>
  <script data-require="[email protected]" data-semver="3.3.7" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
  <script data-require="[email protected]" data-semver="1.6.6" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.min.js"></script>
  <link rel="stylesheet" href="style.css" />
  <script src="script.js"></script>
</head>

<body ng-controller="MainController">
  <div class="dropdown">
    <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
      {{current != null ? current.name : 'DropDown'}}
      <span class="caret"></span>
    </button>
    <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
      <li ng-repeat="item in list">
        <a href="javascript:void(0)" ng-click="select(item)">{{item.name}}</a>
      </li>
    </ul>
  </div>

  <br>

  <form class="form-inline">
    <div class="form-group">
      <label>A</label>
      <input type="text" class="form-control" ng-model="a">
    </div>
    <div class="form-group">
      <label>B</label>
      <input type="text" class="form-control" ng-model="b">
    </div>
  </form>

  <br> result : {{current.watch}}
  <br>
</body>

</html>

Upvotes: 1

Koustubh Kittur
Koustubh Kittur

Reputation: 43

find the following code as your answer see if it helps you.

Script

var app = angular.module('myApp', []);

app.controller('MainController', 
  function($scope) {

    $scope.current = null;
    $scope.select = function(item) {
      $scope.current = item;
    };

    var watch = ['current'];
    $scope.$watchGroup(watch, function() {
      if ($scope.current !== null) {
        watch = ['current'];
        Array.prototype.push.apply(watch, $scope.current.watch);
        $scope.current.callBack();
      }  
    });

    $scope.list = [
        {
          name: 'test-A',
          watch: [' is two times of a'],
          callBack: function() {
            $scope.value = (2 * $scope.a) + ($scope.current.watch);
          }
        },
        {
          name: 'test-B',
          watch: [' is three times of b'],
          callBack: function() {
            $scope.value = (3 * $scope.b) + ($scope.current.watch);
          }
        }
      ];

});

I just concatenated ($scope.current.watch) this with your result

See if it forked to your plnkar.

https://plnkr.co/edit/UGPe4lgJPydEeAXOc0xR?p=preview

Upvotes: 1

Related Questions