Skip to content
This repository was archived by the owner on Oct 2, 2019. It is now read-only.

Feature: Option to not select first item in select-choices by default. #803

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ var uis = angular.module('ui.select', [])
placeholder: '', // Empty by default, like HTML tag <select>
refreshDelay: 1000, // In milliseconds
closeOnSelect: true,
firstItemActive: true,
skipFocusser: false,
dropdownPosition: 'auto',
removeSelected: true,
Expand Down
10 changes: 8 additions & 2 deletions src/uiSelectChoicesDirective.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ uis.directive('uiSelectChoices',

scope.$watch('$select.search', function(newValue) {
if(newValue && !$select.open && $select.multiple) $select.activate(false, true);
$select.activeIndex = $select.tagging.isActivated ? -1 : 0;
$select.activeIndex = $select.tagging.isActivated || !$select.firstItemActive ? -1 : 0;
if (!attrs.minimumInputLength || $select.search.length >= attrs.minimumInputLength) {
$select.refresh(attrs.refresh);
} else {
Expand All @@ -74,7 +74,13 @@ uis.directive('uiSelectChoices',
var refreshDelay = scope.$eval(attrs.refreshDelay);
$select.refreshDelay = refreshDelay !== undefined ? refreshDelay : uiSelectConfig.refreshDelay;
});


attrs.$observe('firstItemActive', function() {
// $eval() is needed otherwise we get a string instead of a boolean
var firstItemActive = scope.$eval(attrs.firstItemActive);
$select.firstItemActive = firstItemActive !== undefined ? firstItemActive : uiSelectConfig.firstItemActive;
});

scope.$watch('$select.open', function(open) {
if (open) {
tElement.attr('role', 'listbox');
Expand Down
18 changes: 14 additions & 4 deletions src/uiSelectController.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ uis.controller('uiSelectCtrl',
ctrl.searchEnabled = uiSelectConfig.searchEnabled;
ctrl.sortable = uiSelectConfig.sortable;
ctrl.refreshDelay = uiSelectConfig.refreshDelay;
ctrl.firstItemActive = uiSelectConfig.firstItemActive;
ctrl.paste = uiSelectConfig.paste;
ctrl.resetSearchInput = uiSelectConfig.resetSearchInput;
ctrl.refreshing = false;
Expand All @@ -26,7 +27,7 @@ uis.controller('uiSelectCtrl',
ctrl.skipFocusser = false; //Set to true to avoid returning focus to ctrl when item is selected
ctrl.search = EMPTY_SEARCH;

ctrl.activeIndex = 0; //Dropdown of choices
ctrl.activeIndex = ctrl.firstItemActive ? 0 : -1; //Dropdown of choices
ctrl.items = []; //All available choices

ctrl.open = false;
Expand Down Expand Up @@ -115,11 +116,13 @@ uis.controller('uiSelectCtrl',

$scope.$broadcast('uis:activate');
ctrl.open = true;
ctrl.activeIndex = ctrl.activeIndex >= ctrl.items.length ? 0 : ctrl.activeIndex;
ctrl.activeIndex = ctrl.activeIndex >= ctrl.items.length ? (ctrl.firstItemActive ? 0 : -1) : ctrl.activeIndex;
// ensure that the index is set to zero for tagging variants
// that where first option is auto-selected
if ( ctrl.activeIndex === -1 && ctrl.taggingLabel !== false ) {
if ( ctrl.firstItemActive && ctrl.activeIndex === -1 && ctrl.taggingLabel !== false ) {
ctrl.activeIndex = 0;
} else {
ctrl.activeIndex = -1;
}

var container = $element.querySelectorAll('.ui-select-choices-content');
Expand Down Expand Up @@ -579,13 +582,20 @@ uis.controller('uiSelectCtrl',
}
break;
case KEY.TAB:
if (!ctrl.multiple || ctrl.open) ctrl.select(ctrl.items[ctrl.activeIndex], true);
if ((!ctrl.multiple || ctrl.open) && ctrl.activeIndex >= 0) {
ctrl.select(ctrl.items[ctrl.activeIndex], true);
} else {
ctrl.close();
}
break;
case KEY.ENTER:
if(ctrl.open && (ctrl.tagging.isActivated || ctrl.activeIndex >= 0)){
ctrl.select(ctrl.items[ctrl.activeIndex], ctrl.skipFocusser); // Make sure at least one dropdown item is highlighted before adding if not in tagging mode
} else {
ctrl.activate(false, true); //In case its the search input in 'multiple' mode
if(!ctrl.firstItemActive) {
ctrl.close();
}
}
break;
case KEY.ESC:
Expand Down
10 changes: 5 additions & 5 deletions src/uiSelectMultipleDirective.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec

if (angular.isUndefined($select.selected))
$select.selected = [];

//Wait for link fn to inject it
$scope.$evalAsync(function(){ ngModel = $scope.ngModel; });

Expand Down Expand Up @@ -289,7 +289,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec

if ( ! KEY.isVerticalMovement(e.which) ) {
scope.$evalAsync( function () {
$select.activeIndex = $select.taggingLabel === false ? -1 : 0;
$select.activeIndex = $select.taggingLabel === false || !$select.firstItemActive ? -1 : 0;
});
}
// Push a "create new" item into array if there is a search string
Expand All @@ -300,7 +300,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
return;
}
// always reset the activeIndex to the first item when tagging
$select.activeIndex = $select.taggingLabel === false ? -1 : 0;
$select.activeIndex = $select.taggingLabel === false || !$select.firstItemActive ? -1 : 0;
// taggingLabel === false bypasses all of this
if ($select.taggingLabel === false) return;

Expand Down Expand Up @@ -370,7 +370,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
if ( hasTag ) {
items = stashArr;
scope.$evalAsync( function () {
$select.activeIndex = 0;
$select.activeIndex = $select.firstItemActive ? 0 : -1;
$select.items = items;
});
}
Expand All @@ -394,7 +394,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
items = items.concat(stashArr);
}
scope.$evalAsync( function () {
$select.activeIndex = 0;
$select.activeIndex = $select.firstItemActive ? 0 : -1;
$select.items = items;

if ($select.isGrouped) {
Expand Down
25 changes: 23 additions & 2 deletions test/select.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1851,12 +1851,13 @@ describe('ui-select tests', function() {
if (attrs.limit !== undefined) { attrsHtml += ' limit="' + attrs.limit + '"'; }
if (attrs.onSelect !== undefined) { attrsHtml += ' on-select="' + attrs.onSelect + '"'; }
if (attrs.removeSelected !== undefined) { attrsHtml += ' remove-selected="' + attrs.removeSelected + '"';}
if (attrs.firstItemActive === undefined) { attrs.firstItemActive = true; }
}

return compileTemplate(
'<ui-select multiple ng-model="selection.selectedMultiple"' + attrsHtml + ' theme="bootstrap" style="width: 800px;"> \
<ui-select-match "' + matchesAttrsHtml + ' placeholder="Pick one...">{{$item.name}} &lt;{{$item.email}}&gt;</ui-select-match> \
<ui-select-choices repeat="person in people | filter: $select.search"' + choicesAttrsHtml + '> \
<ui-select-choices repeat="person in people | filter: $select.search"' + choicesAttrsHtml + ' first-item-active="' + attrs.firstItemActive + '"> \
<div ng-bind-html="person.name | highlight: $select.search"></div> \
<div ng-bind-html="person.email | highlight: $select.search"></div> \
</ui-select-choices> \
Expand Down Expand Up @@ -2191,10 +2192,30 @@ describe('ui-select tests', function() {
var el = createUiSelectMultiple();
var searchInput = el.find('.ui-select-search');

triggerKeydown(searchInput, Key.Down);
triggerKeydown(searchInput, Key.Down); //Open dropdown
el.scope().$select.activeIndex = 0;
triggerKeydown(searchInput, Key.Enter);
expect(scope.selection.selectedMultiple.length).toEqual(2);
});

it('should close choices on ENTER when firstItemActive set to false', function() {

scope.selection.selectedMultiple = [scope.people[5]]; //Samantha
var el = createUiSelectMultiple({firstItemActive: false});
var searchInput = el.find('.ui-select-search');

triggerKeydown(searchInput, Key.Enter);
expect(el.scope().$select.open).toEqual(false);
});

it('should close choices on TAB when firstItemActive set to false', function() {

scope.selection.selectedMultiple = [scope.people[5]]; //Samantha
var el = createUiSelectMultiple({firstItemActive: false});
var searchInput = el.find('.ui-select-search');

triggerKeydown(searchInput, Key.Tab);
expect(el.scope().$select.open).toEqual(false);
});

it('should stop the propagation when pressing ENTER key from dropdown', function() {
Expand Down