@@ -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 when`** `disable` **`for`** `value` **`in`** `array`
97
98
* * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
99
+ * * `label` **`disable when`** `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 when`** `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 when`** `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 when 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
+ // //00001111111111000000000002222222222000000000000000000000333333333300000000000000000000000004444444444400000000000005555555555555550000000006666666666666660000000777777777777777000000000000000888888888800000000000000000009999999999
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 + w h e n \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 when expression (disableWhenFn)
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 disableWhenFn = $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 {
@@ -275,6 +292,12 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
275
292
var label = displayFn ( scope , locals ) ;
276
293
watchedArray . push ( label ) ;
277
294
}
295
+
296
+ // Only need to watch the disableWhenFn if there is a specific disable expression
297
+ if ( match [ 4 ] ) {
298
+ var disableWhen = disableWhenFn ( scope , locals ) ;
299
+ watchedArray . push ( disableWhen ) ;
300
+ }
278
301
} ) ;
279
302
return watchedArray ;
280
303
} ) ,
@@ -300,7 +323,8 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
300
323
var selectValue = getTrackByValue ( viewValue , locals ) ;
301
324
var label = displayFn ( scope , locals ) ;
302
325
var group = groupByFn ( scope , locals ) ;
303
- var optionItem = new Option ( selectValue , viewValue , label , group ) ;
326
+ var disabled = disableWhenFn ( scope , locals ) ;
327
+ var optionItem = new Option ( selectValue , viewValue , label , group , disabled ) ;
304
328
305
329
optionItems . push ( optionItem ) ;
306
330
selectValueMap [ selectValue ] = optionItem ;
@@ -326,7 +350,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
326
350
return {
327
351
restrict : 'A' ,
328
352
terminal : true ,
329
- require : [ 'select' , '? ngModel' ] ,
353
+ require : [ 'select' , 'ngModel' ] ,
330
354
link : function ( scope , selectElement , attr , ctrls ) {
331
355
332
356
// if ngModel is not defined, we don't need to do anything
@@ -377,7 +401,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
377
401
selectCtrl . writeValue = function writeNgOptionsValue ( value ) {
378
402
var option = options . getOptionFromViewValue ( value ) ;
379
403
380
- if ( option ) {
404
+ if ( option && ! option . disabled ) {
381
405
if ( selectElement [ 0 ] . value !== option . selectValue ) {
382
406
removeUnknownOption ( ) ;
383
407
removeEmptyOption ( ) ;
@@ -401,7 +425,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
401
425
402
426
var selectedOption = options . selectValueMap [ selectElement . val ( ) ] ;
403
427
404
- if ( selectedOption ) {
428
+ if ( selectedOption && ! selectedOption . disabled ) {
405
429
removeEmptyOption ( ) ;
406
430
removeUnknownOption ( ) ;
407
431
return selectedOption . viewValue ;
@@ -426,18 +450,22 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
426
450
if ( value ) {
427
451
value . forEach ( function ( item ) {
428
452
var option = options . getOptionFromViewValue ( item ) ;
429
- if ( option ) option . element . selected = true ;
453
+ if ( option && ! option . disabled ) option . element . selected = true ;
430
454
} ) ;
431
455
}
432
456
} ;
433
457
434
458
435
459
selectCtrl . readValue = function readNgOptionsMultiple ( ) {
436
- var selectedValues = selectElement . val ( ) || [ ] ;
437
- return selectedValues . map ( function ( selectedKey ) {
438
- var option = options . selectValueMap [ selectedKey ] ;
439
- return option . viewValue ;
460
+ var selectedValues = selectElement . val ( ) || [ ] ,
461
+ selections = [ ] ;
462
+
463
+ forEach ( selectedValues , function ( value ) {
464
+ var option = options . selectValueMap [ value ] ;
465
+ if ( ! option . disabled ) selections . push ( option . viewValue ) ;
440
466
} ) ;
467
+
468
+ return selections ;
441
469
} ;
442
470
}
443
471
@@ -470,6 +498,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
470
498
471
499
function updateOptionElement ( option , element ) {
472
500
option . element = element ;
501
+ element . disabled = option . disabled ;
473
502
if ( option . value !== element . value ) element . value = option . selectValue ;
474
503
if ( option . label !== element . label ) {
475
504
element . label = option . label ;
0 commit comments