AngularJS/JavaScript实现已选选项不显示在其他下拉框及选中项不消失
Got it, let's work through this problem. Your initial thought of tracking selected IDs is on the right track, but we need to tweak it so each dropdown only excludes selections from other dropdowns (while keeping its own selected option visible, even when filtered). Here's a complete, tested implementation:
Core Idea
Each dropdown needs to know two key things:
- Its own currently selected item (so we never filter this out, no matter what)
- All selected IDs from other dropdowns (so we exclude these from its available options)
This ensures selected options stay unique across dropdowns, and your current dropdown's choice remains visible even if you apply a filter that wouldn't normally match it.
Full Code Example
HTML
<div ng-app="exclusiveDropdownsApp" ng-controller="DropdownController"> <!-- Add new dropdown button --> <button ng-click="addDropdown()">Add New Dropdown</button> <!-- Repeat for each dropdown --> <div ng-repeat="dropdown in dropdowns track by dropdown.id" class="dropdown-container"> <h4>Dropdown {{dropdown.id}}</h4> <!-- Filter input (to test persistent selected option behavior) --> <input type="text" ng-model="dropdown.filterText" placeholder="Filter options..."> <!-- The select element with custom filter logic --> <select ng-model="dropdown.selectedItem" ng-options="item as item.name for item in items | excludeSelected: dropdown.selectedItem.id : getOtherSelectedIds(dropdown.id) | filter: dropdown.filterText" ng-change="onDropdownChange(dropdown)"> <option value="">-- Select an option --</option> </select> </div> </div>
JavaScript
angular.module('exclusiveDropdownsApp', []) .controller('DropdownController', function($scope) { // Original list of all available options $scope.items = [ { id: 1, name: 'Option 1' }, { id: 2, name: 'Option 2' }, { id: 3, name: 'Option 3' }, { id: 4, name: 'Option 4' }, { id: 5, name: 'Option 5' } ]; // Track all dropdowns and their individual state $scope.dropdowns = [ { id: 1, selectedItem: null, filterText: '' } ]; // Add a new empty dropdown dynamically $scope.addDropdown = function() { const newId = $scope.dropdowns.length + 1; $scope.dropdowns.push({ id: newId, selectedItem: null, filterText: '' }); }; // Get all selected IDs EXCEPT the current dropdown's selection $scope.getOtherSelectedIds = function(currentDropdownId) { return $scope.dropdowns .filter(d => d.id !== currentDropdownId && d.selectedItem) .map(d => d.selectedItem.id); }; // Handle dropdown selection change (optional cleanup for edge cases) $scope.onDropdownChange = function(dropdown) { // No mandatory logic here, but you could add checks if you modify the items list later }; }) // Custom filter to exclude cross-dropdown selections while preserving current choice .filter('excludeSelected', function() { return function(items, currentSelectedId, excludedIds) { return items.filter(item => { // Always keep the current dropdown's selected item, even if filter text doesn't match if (item.id === currentSelectedId) { return true; } // Exclude items that are already selected in other dropdowns return !excludedIds.includes(item.id); }); }; });
Key Details Explained
- Dropdown State Tracking: We use an array
dropdownsto manage each dropdown's selected item and filter text. This makes it easy to add/remove dropdowns dynamically without breaking the logic. - Custom Filter
excludeSelected:- Takes three parameters: the full items list, the current dropdown's selected ID, and the list of IDs selected in other dropdowns.
- Forces the current dropdown's selected item to stay visible, even if the filter text doesn't match its name.
- Excludes any items that are already picked in other dropdowns to avoid duplicates.
getOtherSelectedIdsFunction: This generates the list of IDs to exclude for each dropdown by filtering out the current dropdown's own selection—so we never accidentally hide the user's current choice.- Filter Compatibility: The standard
filter: dropdown.filterTextruns after our custom filter, but since we've already locked in the current selected item, it will remain visible regardless of the filter input.
Testing the Implementation
- Select an option in one dropdown: it will disappear from all other dropdowns immediately.
- Type a filter text that doesn't match your selected option: the selected option stays visible, while other options are filtered normally.
- Add new dropdowns with the button: each new dropdown will respect all existing selections automatically.
This approach avoids the "wrong filtering" issue you were worried about because each dropdown only excludes selections from other dropdowns, not its own.
内容的提问来源于stack exchange,提问作者jula k

