Search code examples
angularjshtml-selectangularjs-modelangularjs-watch

Angularjs updates the view but not the model


please pay attention this is the opposite of 99% of the related questions on stackoverflow.

Mi problem is: I have a dependent select, when the 'Master' select changes, the 'Slave' view gets updated but NOT it's model. WEIRD.

Example code:

<!DOCTYPE html>
<html ng-app>

<head>
  <script src="https://code.angularjs.org/1.3.5/angular.js"></script>
</head>

<body>
  <select ng-model='master'>
    <option value='m1'>Master 1</option>
    <option value='m2'>Master 2</option>
  </select>
  <select ng-model='slave'>
    <option value='Slave 1 selected' ng-selected='master == "m1"'>Slave 1</option>
    <option value='Slave 2 selected' ng-selected='master == "m2"'>Slave 2</option>
  </select>
  {{ slave }}
</body>

</html>

When changing the Master select, you can see the select changing but not the printed value for the binding {{ slave }}.

Link to plunker: http://plnkr.co/edit/LjaKgTTfBlczkGuCIhZ1


Solution

  • Angular updates the view based on model changes and the model based on user interactions with the view. By changing the selected option manually using ng-selected, angular has not seen the user select a new option and therefore does not update slave. And since slave has not changed since it last set the selected option on the control it will not update the selected option. I don't think you should use ng-model and ng-selected together. I think this makes total sense and is not a bug in angular, ng-selected just isn't meant to be used that way. Think about this code:

    $scope.buttonClicked = function () {
      $scope.slave = "Slave 1 selected";
      $scope.master = "m2";
    };
    

    What should the value of slave be and which option should be selected? You have set both options in code, what should angular do to the html select? Should it ignore your setting of the 'slave' value? Should it ignore the ng-selected attribute that says it should select slave 2 if master is m2? Let's say you set master to m1, this causes ng-selected to make the selected option slave 1. What if the user then changes the option to slave 2? The ng-selected option is then incorrect.

    If you want to do a one-time setting of the slave value when the master is changed, you should create a watch to run code when the value changes:

    $scope.$watch('master', function(newValue, oldValue) {
      if (newValue == 'm1') {
        $scope.slave = 'Slave 1 selected';
      } else if (newValue == 'm2') {
        $scope.slave = 'Slave 2 selected';
      } else {
        $scope.slave = undefined;
      }
    });