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

Commit 86ca206

Browse files
author
Brett Knighton
committed
Feature: Option to not select first item in select-choices by default.
1 parent 948d383 commit 86ca206

File tree

5 files changed

+40
-20
lines changed

5 files changed

+40
-20
lines changed

src/common.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ var uis = angular.module('ui.select', [])
9393
placeholder: '', // Empty by default, like HTML tag <select>
9494
refreshDelay: 1000, // In milliseconds
9595
closeOnSelect: true,
96+
firstItemActive: true,
9697
generateId: function() {
9798
return latestId++;
9899
},

src/uiSelectChoicesDirective.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ uis.directive('uiSelectChoices',
5151

5252
scope.$watch('$select.search', function(newValue) {
5353
if(newValue && !$select.open && $select.multiple) $select.activate(false, true);
54-
$select.activeIndex = $select.tagging.isActivated ? -1 : 0;
54+
$select.activeIndex = $select.tagging.isActivated || !$select.firstItemActive ? -1 : 0;
5555
$select.refresh(attrs.refresh);
5656
});
5757

@@ -60,6 +60,12 @@ uis.directive('uiSelectChoices',
6060
var refreshDelay = scope.$eval(attrs.refreshDelay);
6161
$select.refreshDelay = refreshDelay !== undefined ? refreshDelay : uiSelectConfig.refreshDelay;
6262
});
63+
64+
attrs.$observe('firstItemActive', function() {
65+
// $eval() is needed otherwise we get a string instead of a boolean
66+
var firstItemActive = scope.$eval(attrs.firstItemActive);
67+
$select.firstItemActive = firstItemActive !== undefined ? firstItemActive : uiSelectConfig.firstItemActive;
68+
});
6369
};
6470
}
6571
};

src/uiSelectController.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ uis.controller('uiSelectCtrl',
1616
ctrl.searchEnabled = uiSelectConfig.searchEnabled;
1717
ctrl.sortable = uiSelectConfig.sortable;
1818
ctrl.refreshDelay = uiSelectConfig.refreshDelay;
19+
ctrl.firstItemActive = uiSelectConfig.firstItemActive;
1920

2021
ctrl.removeSelected = false; //If selected item(s) should be removed from dropdown list
2122
ctrl.closeOnSelect = true; //Initialized inside uiSelect directive link function
2223
ctrl.search = EMPTY_SEARCH;
2324

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

2728
ctrl.open = false;
@@ -43,7 +44,7 @@ uis.controller('uiSelectCtrl',
4344
if (ctrl.searchInput.length !== 1) {
4445
throw uiSelectMinErr('searchInput', "Expected 1 input.ui-select-search but got '{0}'.", ctrl.searchInput.length);
4546
}
46-
47+
4748
ctrl.isEmpty = function() {
4849
return angular.isUndefined(ctrl.selected) || ctrl.selected === null || ctrl.selected === '';
4950
};
@@ -68,12 +69,14 @@ uis.controller('uiSelectCtrl',
6869

6970
ctrl.open = true;
7071

71-
ctrl.activeIndex = ctrl.activeIndex >= ctrl.items.length ? 0 : ctrl.activeIndex;
72+
ctrl.activeIndex = ctrl.activeIndex >= ctrl.items.length ? (ctrl.firstItemActive ? 0 : -1) : ctrl.activeIndex;
7273

7374
// ensure that the index is set to zero for tagging variants
7475
// that where first option is auto-selected
75-
if ( ctrl.activeIndex === -1 && ctrl.taggingLabel !== false ) {
76+
if ( ctrl.firstItemActive && ctrl.activeIndex === -1 && ctrl.taggingLabel !== false ) {
7677
ctrl.activeIndex = 0;
78+
} else {
79+
ctrl.activeIndex = -1;
7780
}
7881

7982
// Give it time to appear before focus
@@ -375,13 +378,20 @@ uis.controller('uiSelectCtrl',
375378
else if (ctrl.activeIndex > 0 || (ctrl.search.length === 0 && ctrl.tagging.isActivated && ctrl.activeIndex > -1)) { ctrl.activeIndex--; }
376379
break;
377380
case KEY.TAB:
378-
if (!ctrl.multiple || ctrl.open) ctrl.select(ctrl.items[ctrl.activeIndex], true);
381+
if ((!ctrl.multiple || ctrl.open) && ctrl.activeIndex >= 0) {
382+
ctrl.select(ctrl.items[ctrl.activeIndex], true);
383+
} else {
384+
ctrl.close();
385+
}
379386
break;
380387
case KEY.ENTER:
381388
if(ctrl.open && ctrl.activeIndex >= 0){
382389
ctrl.select(ctrl.items[ctrl.activeIndex]); // Make sure at least one dropdown item is highlighted before adding.
383390
} else {
384391
ctrl.activate(false, true); //In case its the search input in 'multiple' mode
392+
if(!ctrl.firstItemActive) {
393+
ctrl.close();
394+
}
385395
}
386396
break;
387397
case KEY.ESC:

src/uiSelectMultipleDirective.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
99
$select = $scope.$select,
1010
ngModel;
1111

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

1515
ctrl.activeMatchIndex = -1;
@@ -21,7 +21,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
2121

2222
ctrl.refreshComponent = function(){
2323
//Remove already selected items
24-
//e.g. When user clicks on a selection, the selected array changes and
24+
//e.g. When user clicks on a selection, the selected array changes and
2525
//the dropdown should remove that item
2626
$select.refreshItems();
2727
$select.sizeSearchInput();
@@ -120,7 +120,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
120120
};
121121
if (!inputValue) return resultMultiple; //If ngModel was undefined
122122
for (var k = inputValue.length - 1; k >= 0; k--) {
123-
//Check model array of currently selected items
123+
//Check model array of currently selected items
124124
if (!checkFnMultiple($select.selected, inputValue[k])){
125125
//Check model array of all items available
126126
if (!checkFnMultiple(data, inputValue[k])){
@@ -131,8 +131,8 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
131131
}
132132
return resultMultiple;
133133
});
134-
135-
//Watch for external model changes
134+
135+
//Watch for external model changes
136136
scope.$watchCollection(function(){ return ngModel.$modelValue; }, function(newValue, oldValue) {
137137
if (oldValue != newValue){
138138
ngModel.$modelValue = null; //Force scope model value and ngModel value to be out of sync to re-run formatters
@@ -253,7 +253,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
253253

254254
if ( ! KEY.isVerticalMovement(e.which) ) {
255255
scope.$evalAsync( function () {
256-
$select.activeIndex = $select.taggingLabel === false ? -1 : 0;
256+
$select.activeIndex = $select.taggingLabel === false || !$select.firstItemActive ? -1 : 0;
257257
});
258258
}
259259
// Push a "create new" item into array if there is a search string
@@ -264,7 +264,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
264264
return;
265265
}
266266
// always reset the activeIndex to the first item when tagging
267-
$select.activeIndex = $select.taggingLabel === false ? -1 : 0;
267+
$select.activeIndex = $select.taggingLabel === false || !$select.firstItemActive ? -1 : 0;
268268
// taggingLabel === false bypasses all of this
269269
if ($select.taggingLabel === false) return;
270270

@@ -324,7 +324,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
324324
if ( hasTag ) {
325325
items = stashArr;
326326
scope.$evalAsync( function () {
327-
$select.activeIndex = 0;
327+
$select.activeIndex = $select.firstItemActive ? 0 : -1;
328328
$select.items = items;
329329
});
330330
}
@@ -348,7 +348,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
348348
items = items.concat(stashArr);
349349
}
350350
scope.$evalAsync( function () {
351-
$select.activeIndex = 0;
351+
$select.activeIndex = $select.firstItemActive ? 0 : -1;
352352
$select.items = items;
353353
});
354354
}
@@ -398,4 +398,4 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
398398

399399
}
400400
};
401-
}]);
401+
}]);

test/select.spec.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ describe('ui-select tests', function() {
211211

212212
expect(getMatchLabel(el)).toEqual('Adam');
213213
});
214-
214+
215215
it('should correctly render initial state with track by feature', function() {
216216
var el = compileTemplate(
217217
'<ui-select ng-model="selection.selected"> \
@@ -319,13 +319,13 @@ describe('ui-select tests', function() {
319319
it('should toggle allow-clear directive', function() {
320320
scope.selection.selected = scope.people[0];
321321
scope.isClearAllowed = false;
322-
322+
323323
var el = createUiSelect({theme : 'select2', allowClear: '{{isClearAllowed}}'});
324324
var $select = el.scope().$select;
325325

326326
expect($select.allowClear).toEqual(false);
327327
expect(el.find('.select2-search-choice-close').length).toEqual(0);
328-
328+
329329
// Turn clear on
330330
scope.isClearAllowed = true;
331331
scope.$digest();
@@ -1238,7 +1238,7 @@ describe('ui-select tests', function() {
12381238
return compileTemplate(
12391239
'<ui-select multiple ng-model="selection.selectedMultiple"' + attrsHtml + ' theme="bootstrap" style="width: 800px;"> \
12401240
<ui-select-match placeholder="Pick one...">{{$item.name}} &lt;{{$item.email}}&gt;</ui-select-match> \
1241-
<ui-select-choices repeat="person in people | filter: $select.search"> \
1241+
<ui-select-choices repeat="person in people | filter: $select.search" first-item-active="true"> \
12421242
<div ng-bind-html="person.name | highlight: $select.search"></div> \
12431243
<div ng-bind-html="person.email | highlight: $select.search"></div> \
12441244
</ui-select-choices> \
@@ -1504,6 +1504,9 @@ describe('ui-select tests', function() {
15041504
var el = createUiSelectMultiple();
15051505
var searchInput = el.find('.ui-select-search');
15061506

1507+
triggerKeydown(searchInput, Key.Down); //Open dropdown
1508+
el.scope().$select.activeIndex = 0
1509+
15071510
triggerKeydown(searchInput, Key.Down)
15081511
triggerKeydown(searchInput, Key.Enter)
15091512
expect(scope.selection.selectedMultiple.length).toEqual(2);

0 commit comments

Comments
 (0)