Search code examples
angularjsangularjs-directiveangularjs-scope

How to select an option with multiple duplicate selects without updating all the selects?


I have multiple select tags that use ng-options in each. They all display from the same array of items. However, when I select one item, all the select gets updated to that item. Is there a way to prevent this?

<select ng-model="selectedClass" ng-options="className as className for className in classes track">
        <option value="" disabled selected>Select Class</option>
</select>
<select ng-model="selectedClass" ng-options="className as className for className in classes track">
        <option value="" disabled selected>Select Class</option>
</select>
<select ng-model="selectedClass" ng-options="className as className for className in classes track">
        <option value="" disabled selected>Select Class</option>
</select>

Solution

  • All the selects are getting updated because they all reference the same ng-model.

    If each select should be independent, they must use different models:

    var myApp = angular.module('myApp', []);
    
    function MyCtrl($scope) {
      $scope.classes = ['A', 'B', 'C'];
    }
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    
    <div ng-app="myApp" ng-controller="MyCtrl">
    
      <!--selectedClass1-->
      <select ng-model="selectedClass1" ng-options="className as className for className in classes">
        <option value="" disabled selected>Select Class</option>
      </select>
    
      <!--selectedClass2-->
      <select ng-model="selectedClass2" ng-options="className as className for className in classes">
        <option value="" disabled selected>Select Class</option>
      </select>
    
      <!--selectedClass3-->
      <select ng-model="selectedClass3" ng-options="className as className for className in classes">
        <option value="" disabled selected>Select Class</option>
      </select>
      
      <div>selectedClass1: {{selectedClass1}}</div>
      <div>selectedClass2: {{selectedClass2}}</div>
      <div>selectedClass3: {{selectedClass3}}</div>
    </div>

    If you're using a directive, you can pass the model into the directive's isolate scope:

    angular.module('myApp', [])
      .controller('MyCtrl', ['$scope', MyCtrl])
      .directive('mySelect', mySelect)
    
    function MyCtrl($scope) {
      $scope.selections = [];
    
      $scope.classes = ['A', 'B', 'C'];
    
      $scope.addSelect = function() {
        $scope.selections.push({
          selectedClass: null
        });
      };
    
      $scope.removeSelect = function(index) {
        $scope.selections.splice(index, 1);
      }
    }
    
    function mySelect() {
      return {
        restrict: 'E',
        scope: {
          selection: '=',
          classes: '='
        },
        template: '<select' +
          ' ng-model="selection.selectedClass"' +
          ' ng-options="className as className for className in classes">' +
          '<option value="" disabled selected>Select Class</option>' +
          '</select>'
      }
    }
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    
    <div ng-app="myApp" ng-controller="MyCtrl">
    
      <div ng-repeat="selection in selections">
        <my-select selection="selection" classes="classes"></my-select>
        <button ng-click="removeSelect($index)">Remove</button>
      </div>
    
      <button ng-click="addSelect()">Add a select</button>
    
      <div>selections: {{selections}}</div>
    </div>