Skip to content

Commit 312eda2

Browse files
committed
Merge pull request bentorfs#6 from bentorfs/release/1.1
Release/1.1
2 parents 0be3284 + 0bb686e commit 312eda2

13 files changed

+749
-106
lines changed

dist/angular-bootstrap-multiselect-templates.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ angular.module('btorfs.multiselect.templates', ['multiselect.html']);
33
angular.module("multiselect.html", []).run(["$templateCache", function($templateCache) {
44
$templateCache.put("multiselect.html",
55
"<div class=\"btn-group\" style=\"width: 100%\">\n" +
6-
" <button type=\"button\" class=\"form-control btn btn-default btn-block dropdown-toggle\" ng-click=\"toggleDropdown()\">\n" +
7-
" {{getButtonText()}}&nbsp;<span class=\"caret\"></span></button>\n" +
6+
" <button type=\"button\" class=\"form-control btn btn-default btn-block dropdown-toggle\" ng-click=\"toggleDropdown()\" ng-disabled=\"disabled\">\n" +
7+
" {{getButtonText()}}&nbsp;<span class=\"caret\"></span>\n" +
8+
" </button>\n" +
89
" <ul class=\"dropdown-menu dropdown-menu-form\"\n" +
910
" ng-style=\"{display: open ? 'block' : 'none'}\" style=\"width: 100%; overflow-x: auto\">\n" +
1011
"\n" +
@@ -22,32 +23,33 @@ angular.module("multiselect.html", []).run(["$templateCache", function($template
2223
" class=\"divider\">\n" +
2324
" </li>\n" +
2425
"\n" +
25-
" <li role=\"presentation\" ng-repeat=\"option in selection\" class=\"active\">\n" +
26+
" <li role=\"presentation\" ng-repeat=\"option in selectedOptions\" class=\"active\">\n" +
2627
" <a class=\"item-selected\" href=\"\" ng-click=\"toggleItem(option); $event.stopPropagation()\">\n" +
2728
" <span class=\"glyphicon glyphicon-remove\"></span>\n" +
2829
" {{getDisplay(option)}}\n" +
2930
" </a>\n" +
3031
" </li>\n" +
31-
" <li ng-show=\"selection.length > 0\" class=\"divider\"></li>\n" +
32+
" <li ng-show=\"selectedOptions.length > 0\" class=\"divider\"></li>\n" +
3233
"\n" +
3334
" <li ng-show=\"showSearch\">\n" +
3435
" <div class=\"dropdown-header\">\n" +
3536
" <input type=\"text\" class=\"form-control input-sm\" style=\"width: 100%;\"\n" +
36-
" ng-model=\"searchFilter\" placeholder=\"Search...\"/>\n" +
37+
" ng-model=\"searchFilter\" placeholder=\"Search...\" ng-change=\"updateOptions()\"/>\n" +
3738
" </div>\n" +
3839
" </li>\n" +
3940
"\n" +
4041
" <li ng-show=\"showSearch\" class=\"divider\"></li>\n" +
41-
" <li role=\"presentation\" ng-repeat=\"option in options | filter:search() | limitTo: searchLimit\"\n" +
42-
" ng-if=\"!isSelected(option)\">\n" +
42+
" <li role=\"presentation\" ng-repeat=\"option in unselectedOptions | filter:search() | limitTo: searchLimit\"\n" +
43+
" ng-if=\"!isSelected(option)\"\n" +
44+
" ng-class=\"{disabled : selectionLimit && selectedOptions.length >= selectionLimit}\">\n" +
4345
" <a class=\"item-unselected\" href=\"\" ng-click=\"toggleItem(option); $event.stopPropagation()\">\n" +
4446
" {{getDisplay(option)}}\n" +
4547
" </a>\n" +
4648
" </li>\n" +
4749
"\n" +
4850
" <li class=\"divider\" ng-show=\"selectionLimit > 1\"></li>\n" +
4951
" <li role=\"presentation\" ng-show=\"selectionLimit > 1\">\n" +
50-
" <a>{{selection.length || 0}} / {{selectionLimit}} selected</a>\n" +
52+
" <a>{{selectedOptions.length || 0}} / {{selectionLimit}} selected</a>\n" +
5153
" </li>\n" +
5254
"\n" +
5355
" </ul>\n" +

dist/angular-bootstrap-multiselect.js

Lines changed: 99 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
}, object)
1414
};
1515

16-
multiselect.directive('multiselect', ['$filter', '$document', function ($filter, $document) {
16+
multiselect.directive('multiselect', ['$filter', '$document', '$log', function ($filter, $document, $log) {
1717
return {
1818
restrict: 'AE',
1919
scope: {
@@ -24,7 +24,9 @@
2424
selectionLimit: '=?',
2525
showSelectAll: '=?',
2626
showUnselectAll: '=?',
27-
showSearch: '=?'
27+
showSearch: '=?',
28+
searchFilter: '=?',
29+
disabled: '=?ngDisabled'
2830
},
2931
require: 'ngModel',
3032
templateUrl: 'multiselect.html',
@@ -34,6 +36,14 @@
3436

3537
$scope.searchFilter = '';
3638

39+
if (typeof $scope.options !== 'function') {
40+
$scope.resolvedOptions = $scope.options;
41+
}
42+
43+
if (typeof $attrs.disabled != 'undefined') {
44+
$scope.disabled = true;
45+
}
46+
3747
$scope.toggleDropdown = function () {
3848
$scope.open = !$scope.open;
3949
};
@@ -48,12 +58,35 @@
4858

4959
$document.on('click', closeHandler);
5060

61+
var updateSelectionLists = function () {
62+
if (!$ngModelCtrl.$viewValue) {
63+
if ($scope.selectedOptions) {
64+
$scope.selectedOptions = [];
65+
}
66+
$scope.unselectedOptions = angular.copy($scope.resolvedOptions);
67+
} else {
68+
$scope.selectedOptions = $scope.resolvedOptions.filter(function (el) {
69+
var id = $scope.getId(el);
70+
for (var i = 0; i < $ngModelCtrl.$viewValue.length; i++) {
71+
var selectedId = $scope.getId($ngModelCtrl.$viewValue[i]);
72+
if (id === selectedId) {
73+
return true;
74+
}
75+
}
76+
return false;
77+
});
78+
$scope.unselectedOptions = $scope.resolvedOptions.filter(function (el) {
79+
return $scope.selectedOptions.indexOf(el) < 0;
80+
});
81+
}
82+
};
83+
5184
$ngModelCtrl.$render = function () {
52-
$scope.selection = $ngModelCtrl.$viewValue;
85+
updateSelectionLists();
5386
};
5487

5588
$ngModelCtrl.$viewChangeListeners.push(function () {
56-
$scope.selection = $ngModelCtrl.$viewValue;
89+
updateSelectionLists();
5790
});
5891

5992
$ngModelCtrl.$isEmpty = function (value) {
@@ -64,8 +97,8 @@
6497
}
6598
};
6699

67-
var watcher = $scope.$watch('selection', function () {
68-
$ngModelCtrl.$setViewValue(angular.copy($scope.selection));
100+
var watcher = $scope.$watch('selectedOptions', function () {
101+
$ngModelCtrl.$setViewValue(angular.copy($scope.selectedOptions));
69102
}, true);
70103

71104
$scope.$on('$destroy', function () {
@@ -76,12 +109,12 @@
76109
});
77110

78111
$scope.getButtonText = function () {
79-
if ($scope.selection && $scope.selection.length === 1) {
80-
return $scope.getDisplay($scope.selection[0]);
112+
if ($scope.selectedOptions && $scope.selectedOptions.length === 1) {
113+
return $scope.getDisplay($scope.selectedOptions[0]);
81114
}
82-
if ($scope.selection && $scope.selection.length > 1) {
115+
if ($scope.selectedOptions && $scope.selectedOptions.length > 1) {
83116
var totalSelected;
84-
totalSelected = angular.isDefined($scope.selection) ? $scope.selection.length : 0;
117+
totalSelected = angular.isDefined($scope.selectedOptions) ? $scope.selectedOptions.length : 0;
85118
if (totalSelected === 0) {
86119
return 'Select';
87120
} else {
@@ -93,37 +126,41 @@
93126
};
94127

95128
$scope.selectAll = function () {
96-
$scope.unselectAll();
97-
angular.forEach($scope.options, function (value) {
98-
$scope.toggleItem(value);
99-
});
129+
$scope.selectedOptions = $scope.resolvedOptions;
130+
$scope.unselectedOptions = [];
100131
};
101132

102133
$scope.unselectAll = function () {
103-
$scope.selection = [];
134+
$scope.selectedOptions = [];
135+
$scope.unselectedOptions = $scope.resolvedOptions;
104136
};
105137

106138
$scope.toggleItem = function (item) {
107-
if (typeof $scope.selection === 'undefined') {
108-
$scope.selection = [];
139+
if (typeof $scope.selectedOptions === 'undefined') {
140+
$scope.selectedOptions = [];
109141
}
110-
var index = $scope.selection.indexOf(item);
111-
var exists = index !== -1;
112-
if (exists) {
113-
$scope.selection.splice(index, 1);
114-
} else if (!exists && ($scope.selectionLimit === 0 || $scope.selection.length < $scope.selectionLimit)) {
115-
if (!angular.isDefined($scope.selection) || $scope.selection == null) {
116-
$scope.selection = [];
117-
}
118-
$scope.selection.push(item);
142+
var selectedIndex = $scope.selectedOptions.indexOf(item);
143+
var currentlySelected = (selectedIndex !== -1);
144+
if (currentlySelected) {
145+
$scope.unselectedOptions.push($scope.selectedOptions[selectedIndex]);
146+
$scope.selectedOptions.splice(selectedIndex, 1);
147+
} else if (!currentlySelected && ($scope.selectionLimit === 0 || $scope.selectedOptions.length < $scope.selectionLimit)) {
148+
var unselectedIndex = $scope.unselectedOptions.indexOf(item);
149+
$scope.unselectedOptions.splice(unselectedIndex, 1);
150+
$scope.selectedOptions.push(item);
119151
}
120152
};
121153

122154
$scope.getId = function (item) {
123155
if (angular.isString(item)) {
124156
return item;
125157
} else if (angular.isObject(item)) {
126-
return multiselect.getRecursiveProperty(item, $scope.idProp);
158+
if ($scope.idProp) {
159+
return multiselect.getRecursiveProperty(item, $scope.idProp);
160+
} else {
161+
$log.error('Multiselect: when using objects as model, a idProp value is mandatory.');
162+
return '';
163+
}
127164
} else {
128165
return item;
129166
}
@@ -133,20 +170,38 @@
133170
if (angular.isString(item)) {
134171
return item;
135172
} else if (angular.isObject(item)) {
136-
return multiselect.getRecursiveProperty(item, $scope.displayProp);
173+
if ($scope.displayProp) {
174+
return multiselect.getRecursiveProperty(item, $scope.displayProp);
175+
} else {
176+
$log.error('Multiselect: when using objects as model, a displayProp value is mandatory.');
177+
return '';
178+
}
137179
} else {
138180
return item;
139181
}
140182
};
141183

142184
$scope.isSelected = function (item) {
143-
var result = false;
144-
angular.forEach($scope.selection, function (selectedElement) {
145-
if ($scope.getId(selectedElement) === $scope.getId(item)) {
146-
result = true;
185+
if (!$scope.selectedOptions) {
186+
return false;
187+
}
188+
var itemId = $scope.getId(item);
189+
for (var i = 0; i < $scope.selectedOptions.length; i++) {
190+
var selectedElement = $scope.selectedOptions[i];
191+
if ($scope.getId(selectedElement) === itemId) {
192+
return true;
147193
}
148-
});
149-
return result;
194+
}
195+
return false;
196+
};
197+
198+
$scope.updateOptions = function () {
199+
if (typeof $scope.options === 'function') {
200+
$scope.options().then(function (resolvedOptions) {
201+
$scope.resolvedOptions = resolvedOptions;
202+
updateSelectionLists();
203+
});
204+
}
150205
};
151206

152207
// This search function is optimized to take into account the search limit.
@@ -180,8 +235,9 @@ angular.module('btorfs.multiselect.templates', ['multiselect.html']);
180235
angular.module("multiselect.html", []).run(["$templateCache", function($templateCache) {
181236
$templateCache.put("multiselect.html",
182237
"<div class=\"btn-group\" style=\"width: 100%\">\n" +
183-
" <button type=\"button\" class=\"form-control btn btn-default btn-block dropdown-toggle\" ng-click=\"toggleDropdown()\">\n" +
184-
" {{getButtonText()}}&nbsp;<span class=\"caret\"></span></button>\n" +
238+
" <button type=\"button\" class=\"form-control btn btn-default btn-block dropdown-toggle\" ng-click=\"toggleDropdown()\" ng-disabled=\"disabled\">\n" +
239+
" {{getButtonText()}}&nbsp;<span class=\"caret\"></span>\n" +
240+
" </button>\n" +
185241
" <ul class=\"dropdown-menu dropdown-menu-form\"\n" +
186242
" ng-style=\"{display: open ? 'block' : 'none'}\" style=\"width: 100%; overflow-x: auto\">\n" +
187243
"\n" +
@@ -199,32 +255,33 @@ angular.module("multiselect.html", []).run(["$templateCache", function($template
199255
" class=\"divider\">\n" +
200256
" </li>\n" +
201257
"\n" +
202-
" <li role=\"presentation\" ng-repeat=\"option in selection\" class=\"active\">\n" +
258+
" <li role=\"presentation\" ng-repeat=\"option in selectedOptions\" class=\"active\">\n" +
203259
" <a class=\"item-selected\" href=\"\" ng-click=\"toggleItem(option); $event.stopPropagation()\">\n" +
204260
" <span class=\"glyphicon glyphicon-remove\"></span>\n" +
205261
" {{getDisplay(option)}}\n" +
206262
" </a>\n" +
207263
" </li>\n" +
208-
" <li ng-show=\"selection.length > 0\" class=\"divider\"></li>\n" +
264+
" <li ng-show=\"selectedOptions.length > 0\" class=\"divider\"></li>\n" +
209265
"\n" +
210266
" <li ng-show=\"showSearch\">\n" +
211267
" <div class=\"dropdown-header\">\n" +
212268
" <input type=\"text\" class=\"form-control input-sm\" style=\"width: 100%;\"\n" +
213-
" ng-model=\"searchFilter\" placeholder=\"Search...\"/>\n" +
269+
" ng-model=\"searchFilter\" placeholder=\"Search...\" ng-change=\"updateOptions()\"/>\n" +
214270
" </div>\n" +
215271
" </li>\n" +
216272
"\n" +
217273
" <li ng-show=\"showSearch\" class=\"divider\"></li>\n" +
218-
" <li role=\"presentation\" ng-repeat=\"option in options | filter:search() | limitTo: searchLimit\"\n" +
219-
" ng-if=\"!isSelected(option)\">\n" +
274+
" <li role=\"presentation\" ng-repeat=\"option in unselectedOptions | filter:search() | limitTo: searchLimit\"\n" +
275+
" ng-if=\"!isSelected(option)\"\n" +
276+
" ng-class=\"{disabled : selectionLimit && selectedOptions.length >= selectionLimit}\">\n" +
220277
" <a class=\"item-unselected\" href=\"\" ng-click=\"toggleItem(option); $event.stopPropagation()\">\n" +
221278
" {{getDisplay(option)}}\n" +
222279
" </a>\n" +
223280
" </li>\n" +
224281
"\n" +
225282
" <li class=\"divider\" ng-show=\"selectionLimit > 1\"></li>\n" +
226283
" <li role=\"presentation\" ng-show=\"selectionLimit > 1\">\n" +
227-
" <a>{{selection.length || 0}} / {{selectionLimit}} selected</a>\n" +
284+
" <a>{{selectedOptions.length || 0}} / {{selectionLimit}} selected</a>\n" +
228285
" </li>\n" +
229286
"\n" +
230287
" </ul>\n" +

0 commit comments

Comments
 (0)