1

I'm trying to remove options from drop downs based on the selections made in other drop downs.

For instance, on page load, I have one drop down, and a button which allows the creation of another drop down.

code for my operation:

<div class="form-inline" ng-repeat="setting in sensor.settings">
<select class="form-control" ng-model="setting.port" ng-options="item.name group by item.type for item in ports track by item.name">
  <option value="">-- Module Port --</option>
</select>
</div>

<a href ng-click="newItem($event, sensor.settings)">New Port</a>

Expected Result:

If only one drop down exists, a user can select any option in it and no additional logic needs to be executed.

However, if the "new port" button is clicked, it'll create additional drop downs with the same options as the first, second, etc... What I'm looking to do is remove the options which are selected in any of the drop downs from those which the option wasn't selected from to prevent duplicate selections.

So for instance, if I have 3 drop downs, and the available selections to all drop downs are D1, D2, and D3; the user selects D1 for the first, which removes option D1 from drop downs 2 & 3. D2 is selected in the second, which removes D2 from drop down 1 & 3, leaving drop down 3 with a single selection of D3.

Here's a link to my code:

Tharif
  • 13,794
  • 9
  • 55
  • 77

1 Answers1

2

I have forked your plunker, and I think I have something that should work for you here.

The important part is that I changed ng-options to use a filtered list of ports, based on the index you're currently looking at. (I changed the ng-repeat to also track the index):

<div class="form-inline" ng-repeat="(index, setting) in sensor.settings">
  <select class="form-control" ng-model="setting.port" ng-options="item.name group by item.type for item in filteredPorts(index) track by item.name" ng-change="updateAll(index)">
    <option value="">-- Module Port --</option>
  </select>
</div>

I then implemented filteredPorts as a function that takes an index and filters out all other selected ports and returns only those as the possible options:

$scope.filteredPorts = function(index) { 
  // Filter out anything that's currently selected elsewhere
  var currentSelections = [];
  $scope.sensor.settings.forEach(function(value, idx) { 
    if (index !== idx) { currentSelections.push(value.port); } // if statement enforces "elsewhere"
  });

Note that I also defined an array diff method, used in the above code:

Array.prototype.diff = function(a) {
  return this.filter(function(i) {return a.indexOf(i) < 0;});
}; // from http://stackoverflow.com/questions/1187518/javascript-array-difference

  return $scope.ports.diff(currentSelections);
}

I also changed the newItem function to just create a new item and not do any filtering:

$scope.newItem = function($event, sensorSetting) {
  $scope.sensor.settings.push({
    port: '',
    room: '',
    device: ''
  });
  $event.preventDefault();
}

Finally, just in case, I added an ng-click handler that deals with any duplicates, but that shouldn't be possible so can probably be ignored.

To explain why it didn't work in the first place and what the main difference here is, you were changing the $scope variable from which all of the <select>s were pulling -- you want to change it for each one individually, which I accomplish here by passing in the index variable to a function.

Carson Moore
  • 1,287
  • 1
  • 8
  • 9