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

Commit 1915b1c

Browse files
author
Brian Feister
committed
Rebase again
Conflicts: src/select.js
2 parents 7ee06b3 + f29d57f commit 1915b1c

File tree

3 files changed

+79
-50
lines changed

3 files changed

+79
-50
lines changed

examples/demo-multi-select.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ <h3>Multi select</h3>
113113
<h1>Multi Selection Demos</h1>
114114

115115
<h3>Array of strings</h3>
116-
<ui-select multiple ng-model="multipleDemo.colors" theme="bootstrap" ng-disabled="disabled" style="width: 300px;">
116+
<ui-select multiple ng-model="multipleDemo.colors" theme="bootstrap" ng-disabled="disabled" close-on-select="false" style="width: 300px;">
117117
<ui-select-match placeholder="Select colors...">{{$item}}</ui-select-match>
118118
<ui-select-choices repeat="color in availableColors | filter:$select.search">
119119
{{color}}
@@ -122,7 +122,7 @@ <h3>Array of strings</h3>
122122
<p>Selected: {{multipleDemo.colors}}</p>
123123
<hr>
124124
<h3>Array of objects</h3>
125-
<ui-select multiple ng-model="multipleDemo.selectedPeople" theme="bootstrap" ng-disabled="disabled" style="width: 800px;">
125+
<ui-select multiple ng-model="multipleDemo.selectedPeople" theme="bootstrap" ng-disabled="disabled" close-on-select="false" style="width: 800px;">
126126
<ui-select-match placeholder="Select person...">{{$item.name}} &lt;{{$item.email}}&gt;</ui-select-match>
127127
<ui-select-choices repeat="person in people | propsFilter: {name: $select.search, age: $select.search}">
128128
<div ng-bind-html="person.name | highlight: $select.search"></div>
@@ -136,7 +136,7 @@ <h3>Array of objects</h3>
136136

137137
<hr>
138138
<h3>Deselect callback with single property binding</h3>
139-
<ui-select multiple ng-model="multipleDemo.deSelectedPeople" on-remove="removed($item, $model)" theme="bootstrap" ng-disabled="disabled" style="width: 800px;">
139+
<ui-select multiple ng-model="multipleDemo.deSelectedPeople" on-remove="removed($item, $model)" theme="bootstrap" ng-disabled="disabled" close-on-select="false" style="width: 800px;">
140140
<ui-select-match placeholder="Select person...">{{$item.name}} &lt;{{$item.email}}&gt;</ui-select-match>
141141
<ui-select-choices repeat="person.email as person in people | propsFilter: {name: $select.search, age: $select.search}">
142142
<div ng-bind-html="person.name | highlight: $select.search"></div>
@@ -151,7 +151,7 @@ <h3>Deselect callback with single property binding</h3>
151151

152152
<hr>
153153
<h3>Array of objects with single property binding</h3>
154-
<ui-select multiple ng-model="multipleDemo.selectedPeopleSimple" theme="bootstrap" ng-disabled="disabled" style="width: 800px;">
154+
<ui-select multiple ng-model="multipleDemo.selectedPeopleSimple" theme="bootstrap" ng-disabled="disabled" close-on-select="false" style="width: 800px;">
155155
<ui-select-match placeholder="Select person...">{{$item.name}} &lt;{{$item.email}}&gt;</ui-select-match>
156156
<ui-select-choices repeat="person.email as person in people | propsFilter: {name: $select.search, age: $select.search}">
157157
<div ng-bind-html="person.name | highlight: $select.search"></div>
@@ -165,7 +165,7 @@ <h3>Array of objects with single property binding</h3>
165165

166166
<hr>
167167
<h3>Array of objects (with groupBy)</h3>
168-
<ui-select multiple ng-model="multipleDemo.selectedPeopleWithGroupBy" theme="bootstrap" ng-disabled="disabled" style="width: 800px;">
168+
<ui-select multiple ng-model="multipleDemo.selectedPeopleWithGroupBy" theme="bootstrap" ng-disabled="disabled" close-on-select="false" style="width: 800px;">
169169
<ui-select-match placeholder="Select person...">{{$item.name}} &lt;{{$item.email}}&gt;</ui-select-match>
170170
<ui-select-choices group-by="someGroupFn" repeat="person in people | propsFilter: {name: $select.search, age: $select.search}">
171171
<div ng-bind-html="person.name | highlight: $select.search"></div>

src/select.js

Lines changed: 57 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@
7171
theme: 'bootstrap',
7272
searchEnabled: true,
7373
placeholder: '', // Empty by default, like HTML tag <select>
74-
refreshDelay: 1000 // In milliseconds
74+
refreshDelay: 1000, // In milliseconds
75+
closeOnSelect: true
7576
})
7677

7778
// See Rename minErr and make it accessible from outside https://github.com/angular/angular.js/issues/6913
@@ -166,6 +167,8 @@
166167
ctrl.tagging = {isActivated: false, fct: undefined};
167168
ctrl.taggingTokens = {isActivated: false, tokens: undefined};
168169
ctrl.lockChoiceExpression = undefined; // Initialized inside uiSelect directive link function
170+
ctrl.closeOnSelect = true; // Initialized inside uiSelect directive link function
171+
ctrl.clickTriggeredSelect = false;
169172

170173
ctrl.isEmpty = function() {
171174
return angular.isUndefined(ctrl.selected) || ctrl.selected === null || ctrl.selected === '';
@@ -346,57 +349,65 @@
346349
return isDisabled;
347350
};
348351

352+
349353
// When the user selects an item with ENTER or clicks the dropdown
350-
ctrl.select = function(item, skipFocusser) {
351-
352-
if ( ! ctrl.items && ! ctrl.search ) return;
353-
354-
if (!item || !item._uiSelectChoiceDisabled) {
355-
if(ctrl.tagging.isActivated) {
356-
// if taggingLabel is disabled, we pull from ctrl.search val
357-
if ( ctrl.taggingLabel === false ) {
358-
if ( ctrl.activeIndex < 0 ) {
359-
item = ctrl.tagging.fct !== undefined ? ctrl.tagging.fct(ctrl.search) : ctrl.search;
360-
if ( angular.equals( ctrl.items[0], item ) ) {
361-
return;
354+
ctrl.select = function(item, skipFocusser, $event) {
355+
if (item === undefined || !item._uiSelectChoiceDisabled) {
356+
357+
if ( ! ctrl.items && ! ctrl.search ) return;
358+
359+
if (!item || !item._uiSelectChoiceDisabled) {
360+
if(ctrl.tagging.isActivated) {
361+
// if taggingLabel is disabled, we pull from ctrl.search val
362+
if ( ctrl.taggingLabel === false ) {
363+
if ( ctrl.activeIndex < 0 ) {
364+
item = ctrl.tagging.fct !== undefined ? ctrl.tagging.fct(ctrl.search) : ctrl.search;
365+
if ( angular.equals( ctrl.items[0], item ) ) {
366+
return;
367+
}
368+
} else {
369+
// keyboard nav happened first, user selected from dropdown
370+
item = ctrl.items[ctrl.activeIndex];
362371
}
363372
} else {
364-
// keyboard nav happened first, user selected from dropdown
365-
item = ctrl.items[ctrl.activeIndex];
373+
// tagging always operates at index zero, taggingLabel === false pushes
374+
// the ctrl.search value without having it injected
375+
if ( ctrl.activeIndex === 0 ) {
376+
// ctrl.tagging pushes items to ctrl.items, so we only have empty val
377+
// for `item` if it is a detected duplicate
378+
if ( item === undefined ) return;
379+
// create new item on the fly
380+
item = ctrl.tagging.fct !== undefined ? ctrl.tagging.fct(ctrl.search) : item.replace(ctrl.taggingLabel,'');
381+
}
366382
}
367-
} else {
368-
// tagging always operates at index zero, taggingLabel === false pushes
369-
// the ctrl.search value without having it injected
370-
if ( ctrl.activeIndex === 0 ) {
371-
// ctrl.tagging pushes items to ctrl.items, so we only have empty val
372-
// for `item` if it is a detected duplicate
373-
if ( item === undefined ) return;
374-
// create new item on the fly
375-
item = ctrl.tagging.fct !== undefined ? ctrl.tagging.fct(ctrl.search) : item.replace(ctrl.taggingLabel,'');
383+
// search ctrl.selected for dupes potentially caused by tagging and return early if found
384+
if ( ctrl.selected && ctrl.selected.filter( function (selection) { return angular.equals(selection, item); }).length > 0 ) {
385+
ctrl.close(skipFocusser);
386+
return;
376387
}
377388
}
378-
// search ctrl.selected for dupes potentially caused by tagging and return early if found
379-
if ( ctrl.selected && ctrl.selected.filter( function (selection) { return angular.equals(selection, item); }).length > 0 ) {
380-
ctrl.close(skipFocusser);
381-
return;
382-
}
383-
}
384389

385-
var locals = {};
386-
locals[ctrl.parserResult.itemName] = item;
390+
var locals = {};
391+
locals[ctrl.parserResult.itemName] = item;
387392

388-
ctrl.onSelectCallback($scope, {
389-
$item: item,
390-
$model: ctrl.parserResult.modelMapper($scope, locals)
391-
});
393+
ctrl.onSelectCallback($scope, {
394+
$item: item,
395+
$model: ctrl.parserResult.modelMapper($scope, locals)
396+
});
392397

393-
if(ctrl.multiple){
394-
ctrl.selected.push(item);
395-
ctrl.sizeSearchInput();
396-
} else {
397-
ctrl.selected = item;
398+
if(ctrl.multiple) {
399+
ctrl.selected.push(item);
400+
ctrl.sizeSearchInput();
401+
} else {
402+
ctrl.selected = item;
403+
}
404+
if (!ctrl.multiple || ctrl.closeOnSelect) {
405+
ctrl.close(skipFocusser);
406+
}
407+
if ($event && $event.type === 'click') {
408+
ctrl.clickTriggeredSelect = true;
409+
}
398410
}
399-
ctrl.close(skipFocusser);
400411
}
401412
};
402413

@@ -813,7 +824,7 @@
813824
var searchInput = element.querySelectorAll('input.ui-select-search');
814825

815826
$select.multiple = (angular.isDefined(attrs.multiple)) ? (attrs.multiple === '') ? true : (attrs.multiple.toLowerCase() === 'true') : false;
816-
827+
$select.closeOnSelect = (angular.isDefined(attrs.closeOnSelect) && attrs.closeOnSelect.toLowerCase() === 'false') ? false : uiSelectConfig.closeOnSelect;
817828
$select.onSelectCallback = $parse(attrs.onSelect);
818829
$select.onRemoveCallback = $parse(attrs.onRemove);
819830

@@ -1051,10 +1062,11 @@
10511062
contains = element[0].contains(e.target);
10521063
}
10531064

1054-
if (!contains) {
1065+
if (!contains && !$select.clickTriggeredSelect) {
10551066
$select.close();
10561067
scope.$digest();
10571068
}
1069+
$select.clickTriggeredSelect = false;
10581070
}
10591071

10601072
// See Click everywhere but here event http://stackoverflow.com/questions/12931369
@@ -1134,7 +1146,7 @@
11341146
choices.attr('ng-repeat', RepeatParser.getNgRepeatExpression($select.parserResult.itemName, '$select.items', $select.parserResult.trackByExp, groupByExp))
11351147
.attr('ng-if', '$select.open') //Prevent unnecessary watches when dropdown is closed
11361148
.attr('ng-mouseenter', '$select.setActiveItem('+$select.parserResult.itemName +')')
1137-
.attr('ng-click', '$select.select(' + $select.parserResult.itemName + ')');
1149+
.attr('ng-click', '$select.select(' + $select.parserResult.itemName + ',false,$event)');
11381150

11391151
var rowsInner = element.querySelectorAll('.ui-select-choices-row-inner');
11401152
if (rowsInner.length !== 1) throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row-inner but got '{0}'.", rowsInner.length);

test/select.spec.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,7 @@ describe('ui-select tests', function() {
10781078
if (attrs.disabled !== undefined) { attrsHtml += ' ng-disabled="' + attrs.disabled + '"'; }
10791079
if (attrs.required !== undefined) { attrsHtml += ' ng-required="' + attrs.required + '"'; }
10801080
if (attrs.tabindex !== undefined) { attrsHtml += ' tabindex="' + attrs.tabindex + '"'; }
1081+
if (attrs.closeOnSelect !== undefined) { attrsHtml += ' close-on-select="' + attrs.closeOnSelect + '"'; }
10811082
}
10821083

10831084
return compileTemplate(
@@ -1313,6 +1314,22 @@ describe('ui-select tests', function() {
13131314

13141315
});
13151316

1317+
it('should not close dropdown after selecting if closeOnSelect=false', function() {
1318+
1319+
scope.selection.selectedMultiple = [scope.people[5]]; //Samantha
1320+
var el = createUiSelectMultiple({closeOnSelect: false});
1321+
var searchInput = el.find('.ui-select-search');
1322+
1323+
expect(isDropdownOpened(el)).toEqual(false);
1324+
triggerKeydown(searchInput, Key.Down)
1325+
expect(isDropdownOpened(el)).toEqual(true);
1326+
1327+
clickItem(el, 'Wladimir');
1328+
1329+
expect(isDropdownOpened(el)).toEqual(true);
1330+
1331+
});
1332+
13161333
it('should closes dropdown when pressing ESC key from search input', function() {
13171334

13181335
scope.selection.selectedMultiple = [scope.people[4], scope.people[5], scope.people[6]]; //Wladimir, Samantha & Nicole

0 commit comments

Comments
 (0)