@@ -94,15 +94,20 @@ var ngOptionsMinErr = minErr('ngOptions');
94
94
* * `label` **`for`** `value` **`in`** `array`
95
95
* * `select` **`as`** `label` **`for`** `value` **`in`** `array`
96
96
* * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
97
+ * * `label` **`disable by`** `disable` **`for`** `value` **`in`** `array`
97
98
* * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
99
+ * * `label` **`disable by`** `disable` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
98
100
* * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
99
101
* (for including a filter with `track by`)
100
102
* * for object data sources:
101
103
* * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
102
104
* * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
103
105
* * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
106
+ * * `label` **`disable by`** `disable` **`for (`**`key`**`,`** `value`**`) in`** `object`
104
107
* * `select` **`as`** `label` **`group by`** `group`
105
108
* **`for` `(`**`key`**`,`** `value`**`) in`** `object`
109
+ * * `select` **`as`** `label` **`disable by`** `disable`
110
+ * **`for` `(`**`key`**`,`** `value`**`) in`** `object`
106
111
*
107
112
* Where:
108
113
*
@@ -116,6 +121,8 @@ var ngOptionsMinErr = minErr('ngOptions');
116
121
* element. If not specified, `select` expression will default to `value`.
117
122
* * `group`: The result of this expression will be used to group options using the `<optgroup>`
118
123
* DOM element.
124
+ * * `disable`: The result of this expression will be used to disable the rendered `<option>`
125
+ * element. Return `true` to disable.
119
126
* * `trackexpr`: Used when working with an array of objects. The result of this expression will be
120
127
* used to identify the objects in the array. The `trackexpr` will most likely refer to the
121
128
* `value` variable (e.g. `value.propertyName`). With this the selection is preserved
@@ -129,10 +136,10 @@ var ngOptionsMinErr = minErr('ngOptions');
129
136
.controller('ExampleController', ['$scope', function($scope) {
130
137
$scope.colors = [
131
138
{name:'black', shade:'dark'},
132
- {name:'white', shade:'light'},
139
+ {name:'white', shade:'light', notAnOption: true },
133
140
{name:'red', shade:'dark'},
134
- {name:'blue', shade:'dark'},
135
- {name:'yellow', shade:'light'}
141
+ {name:'blue', shade:'dark', notAnOption: true },
142
+ {name:'yellow', shade:'light', notAnOption: false }
136
143
];
137
144
$scope.myColor = $scope.colors[2]; // red
138
145
}]);
@@ -141,6 +148,7 @@ var ngOptionsMinErr = minErr('ngOptions');
141
148
<ul>
142
149
<li ng-repeat="color in colors">
143
150
Name: <input ng-model="color.name">
151
+ <input type="checkbox" ng-model="color.notAnOption"> Disabled?
144
152
[<a href ng-click="colors.splice($index, 1)">X</a>]
145
153
</li>
146
154
<li>
@@ -162,6 +170,12 @@ var ngOptionsMinErr = minErr('ngOptions');
162
170
<select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
163
171
</select><br/>
164
172
173
+ Color grouped by shade, with some disabled:
174
+ <select ng-model="myColor"
175
+ ng-options="color.name group by color.shade disable by color.notAnOption for color in colors">
176
+ </select><br/>
177
+
178
+
165
179
166
180
Select <a href ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</a>.<br>
167
181
<hr/>
@@ -186,16 +200,17 @@ var ngOptionsMinErr = minErr('ngOptions');
186
200
*/
187
201
188
202
// jshint maxlen: false
189
- //000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
190
- var NG_OPTIONS_REGEXP = / ^ \s * ( [ \s \S ] + ?) (?: \s + a s \s + ( [ \s \S ] + ?) ) ? (?: \s + g r o u p \s + b y \s + ( [ \s \S ] + ?) ) ? \s + f o r \s + (?: ( [ \$ \w ] [ \$ \w ] * ) | (?: \( \s * ( [ \$ \w ] [ \$ \w ] * ) \s * , \s * ( [ \$ \w ] [ \$ \w ] * ) \s * \) ) ) \s + i n \s + ( [ \s \S ] + ?) (?: \s + t r a c k \s + b y \s + ( [ \s \S ] + ?) ) ? $ / ;
203
+ // //000011111111110000000000022222222220000000000000000000003333333333000000000000000000000004444444444400000000000005555555555555550000000006666666666666660000000777777777777777000000000000000888888888800000000000000000009999999999
204
+ var NG_OPTIONS_REGEXP = / ^ \s * ( [ \s \S ] + ?) (?: \s + a s \s + ( [ \s \S ] + ?) ) ? (?: \s + g r o u p \s + b y \s + ( [ \s \S ] + ?) ) ? (?: \s + d i s a b l e \s + b y \s + ( [ \s \S ] + ? ) ) ? \s + f o r \s + (?: ( [ \$ \w ] [ \$ \w ] * ) | (?: \( \s * ( [ \$ \w ] [ \$ \w ] * ) \s * , \s * ( [ \$ \w ] [ \$ \w ] * ) \s * \) ) ) \s + i n \s + ( [ \s \S ] + ?) (?: \s + t r a c k \s + b y \s + ( [ \s \S ] + ?) ) ? $ / ;
191
205
// 1: value expression (valueFn)
192
206
// 2: label expression (displayFn)
193
207
// 3: group by expression (groupByFn)
194
- // 4: array item variable name
195
- // 5: object item key variable name
196
- // 6: object item value variable name
197
- // 7: collection expression
198
- // 8: track by expression
208
+ // 4: disable by expression (disableByFn)
209
+ // 5: array item variable name
210
+ // 6: object item key variable name
211
+ // 7: object item value variable name
212
+ // 8: collection expression
213
+ // 9: track by expression
199
214
// jshint maxlen: 100
200
215
201
216
@@ -215,14 +230,14 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
215
230
// Extract the parts from the ngOptions expression
216
231
217
232
// The variable name for the value of the item in the collection
218
- var valueName = match [ 4 ] || match [ 6 ] ;
233
+ var valueName = match [ 5 ] || match [ 7 ] ;
219
234
// The variable name for the key of the item in the collection
220
- var keyName = match [ 5 ] ;
235
+ var keyName = match [ 6 ] ;
221
236
222
237
// An expression that generates the viewValue for an option if there is a label expression
223
238
var selectAs = / a s / . test ( match [ 0 ] ) && match [ 1 ] ;
224
239
// An expression that is used to track the id of each object in the options collection
225
- var trackBy = match [ 8 ] ;
240
+ var trackBy = match [ 9 ] ;
226
241
// An expression that generates the viewValue for an option if there is no label expression
227
242
var valueFn = $parse ( match [ 2 ] ? match [ 1 ] : valueName ) ;
228
243
var selectAsFn = selectAs && $parse ( selectAs ) ;
@@ -237,7 +252,8 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
237
252
function getHashOfValue ( viewValue ) { return hashKey ( viewValue ) ; } ;
238
253
var displayFn = $parse ( match [ 2 ] || match [ 1 ] ) ;
239
254
var groupByFn = $parse ( match [ 3 ] || '' ) ;
240
- var valuesFn = $parse ( match [ 7 ] ) ;
255
+ var disableByFn = $parse ( match [ 4 ] || '' ) ;
256
+ var valuesFn = $parse ( match [ 8 ] ) ;
241
257
242
258
var locals = { } ;
243
259
var getLocals = keyName ? function ( value , key ) {
@@ -250,11 +266,12 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
250
266
} ;
251
267
252
268
253
- function Option ( selectValue , viewValue , label , group ) {
269
+ function Option ( selectValue , viewValue , label , group , disabled ) {
254
270
this . selectValue = selectValue ;
255
271
this . viewValue = viewValue ;
256
272
this . label = label ;
257
273
this . group = group ;
274
+ this . disabled = disabled ;
258
275
}
259
276
260
277
return {
@@ -269,8 +286,10 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
269
286
var locals = getLocals ( values [ key ] , key ) ;
270
287
var label = displayFn ( scope , locals ) ;
271
288
var selectValue = getTrackByValue ( values [ key ] , locals ) ;
289
+ var disabledBy = disableByFn ( scope , locals ) ;
272
290
watchedArray . push ( selectValue ) ;
273
291
watchedArray . push ( label ) ;
292
+ watchedArray . push ( disabledBy ) ;
274
293
} ) ;
275
294
return watchedArray ;
276
295
} ) ,
@@ -296,7 +315,8 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
296
315
var selectValue = getTrackByValue ( viewValue , locals ) ;
297
316
var label = displayFn ( scope , locals ) ;
298
317
var group = groupByFn ( scope , locals ) ;
299
- var optionItem = new Option ( selectValue , viewValue , label , group ) ;
318
+ var disabled = disableByFn ( scope , locals ) ;
319
+ var optionItem = new Option ( selectValue , viewValue , label , group , disabled ) ;
300
320
301
321
optionItems . push ( optionItem ) ;
302
322
selectValueMap [ selectValue ] = optionItem ;
@@ -322,7 +342,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
322
342
return {
323
343
restrict : 'A' ,
324
344
terminal : true ,
325
- require : [ 'select' , '? ngModel' ] ,
345
+ require : [ 'select' , 'ngModel' ] ,
326
346
link : function ( scope , selectElement , attr , ctrls ) {
327
347
328
348
// if ngModel is not defined, we don't need to do anything
@@ -373,7 +393,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
373
393
selectCtrl . writeValue = function writeNgOptionsValue ( value ) {
374
394
var option = options . getOptionFromViewValue ( value ) ;
375
395
376
- if ( option ) {
396
+ if ( option && ! option . disabled ) {
377
397
if ( selectElement [ 0 ] . value !== option . selectValue ) {
378
398
removeUnknownOption ( ) ;
379
399
removeEmptyOption ( ) ;
@@ -397,7 +417,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
397
417
398
418
var selectedOption = options . selectValueMap [ selectElement . val ( ) ] ;
399
419
400
- if ( selectedOption ) {
420
+ if ( selectedOption && ! selectedOption . disabled ) {
401
421
removeEmptyOption ( ) ;
402
422
removeUnknownOption ( ) ;
403
423
return selectedOption . viewValue ;
@@ -422,18 +442,22 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
422
442
if ( value ) {
423
443
value . forEach ( function ( item ) {
424
444
var option = options . getOptionFromViewValue ( item ) ;
425
- if ( option ) option . element . selected = true ;
445
+ if ( option && ! option . disabled ) option . element . selected = true ;
426
446
} ) ;
427
447
}
428
448
} ;
429
449
430
450
431
451
selectCtrl . readValue = function readNgOptionsMultiple ( ) {
432
- var selectedValues = selectElement . val ( ) || [ ] ;
433
- return selectedValues . map ( function ( selectedKey ) {
434
- var option = options . selectValueMap [ selectedKey ] ;
435
- return option . viewValue ;
452
+ var selectedValues = selectElement . val ( ) || [ ] ,
453
+ selections = [ ] ;
454
+
455
+ forEach ( selectedValues , function ( value ) {
456
+ var option = options . selectValueMap [ value ] ;
457
+ if ( ! option . disabled ) selections . push ( option . viewValue ) ;
436
458
} ) ;
459
+
460
+ return selections ;
437
461
} ;
438
462
}
439
463
@@ -466,6 +490,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
466
490
467
491
function updateOptionElement ( option , element ) {
468
492
option . element = element ;
493
+ element . disabled = option . disabled ;
469
494
if ( option . value !== element . value ) element . value = option . selectValue ;
470
495
if ( option . label !== element . label ) {
471
496
element . label = option . label ;
0 commit comments