@@ -94,15 +94,20 @@ var ngOptionsMinErr = minErr('ngOptions');
9494 * * `label` **`for`** `value` **`in`** `array`
9595 * * `select` **`as`** `label` **`for`** `value` **`in`** `array`
9696 * * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
97+ * * `label` **`disable by`** `disable` **`for`** `value` **`in`** `array`
9798 * * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
99+ * * `label` **`disable by`** `disable` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
98100 * * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
99101 * (for including a filter with `track by`)
100102 * * for object data sources:
101103 * * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
102104 * * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
103105 * * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
106+ * * `label` **`disable by`** `disable` **`for (`**`key`**`,`** `value`**`) in`** `object`
104107 * * `select` **`as`** `label` **`group by`** `group`
105108 * **`for` `(`**`key`**`,`** `value`**`) in`** `object`
109+ * * `select` **`as`** `label` **`disable by`** `disable`
110+ * **`for` `(`**`key`**`,`** `value`**`) in`** `object`
106111 *
107112 * Where:
108113 *
@@ -116,6 +121,8 @@ var ngOptionsMinErr = minErr('ngOptions');
116121 * element. If not specified, `select` expression will default to `value`.
117122 * * `group`: The result of this expression will be used to group options using the `<optgroup>`
118123 * DOM element.
124+ * * `disable`: The result of this expression will be used to disable the rendered `<option>`
125+ * element. Return `true` to disable.
119126 * * `trackexpr`: Used when working with an array of objects. The result of this expression will be
120127 * used to identify the objects in the array. The `trackexpr` will most likely refer to the
121128 * `value` variable (e.g. `value.propertyName`). With this the selection is preserved
@@ -129,10 +136,10 @@ var ngOptionsMinErr = minErr('ngOptions');
129136 .controller('ExampleController', ['$scope', function($scope) {
130137 $scope.colors = [
131138 {name:'black', shade:'dark'},
132- {name:'white', shade:'light'},
139+ {name:'white', shade:'light', notAnOption: true },
133140 {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 }
136143 ];
137144 $scope.myColor = $scope.colors[2]; // red
138145 }]);
@@ -141,6 +148,7 @@ var ngOptionsMinErr = minErr('ngOptions');
141148 <ul>
142149 <li ng-repeat="color in colors">
143150 Name: <input ng-model="color.name">
151+ <input type="checkbox" ng-model="color.notAnOption"> Disabled?
144152 [<a href ng-click="colors.splice($index, 1)">X</a>]
145153 </li>
146154 <li>
@@ -162,6 +170,12 @@ var ngOptionsMinErr = minErr('ngOptions');
162170 <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
163171 </select><br/>
164172
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+
165179
166180 Select <a href ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</a>.<br>
167181 <hr/>
@@ -186,16 +200,17 @@ var ngOptionsMinErr = minErr('ngOptions');
186200 */
187201
188202// 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 ] + ?) ) ? $ / ;
191205 // 1: value expression (valueFn)
192206 // 2: label expression (displayFn)
193207 // 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
199214// jshint maxlen: 100
200215
201216
@@ -215,14 +230,14 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
215230 // Extract the parts from the ngOptions expression
216231
217232 // 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 ] ;
219234 // The variable name for the key of the item in the collection
220- var keyName = match [ 5 ] ;
235+ var keyName = match [ 6 ] ;
221236
222237 // An expression that generates the viewValue for an option if there is a label expression
223238 var selectAs = / a s / . test ( match [ 0 ] ) && match [ 1 ] ;
224239 // 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 ] ;
226241 // An expression that generates the viewValue for an option if there is no label expression
227242 var valueFn = $parse ( match [ 2 ] ? match [ 1 ] : valueName ) ;
228243 var selectAsFn = selectAs && $parse ( selectAs ) ;
@@ -237,7 +252,8 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
237252 function getHashOfValue ( viewValue ) { return hashKey ( viewValue ) ; } ;
238253 var displayFn = $parse ( match [ 2 ] || match [ 1 ] ) ;
239254 var groupByFn = $parse ( match [ 3 ] || '' ) ;
240- var valuesFn = $parse ( match [ 7 ] ) ;
255+ var disableByFn = $parse ( match [ 4 ] || '' ) ;
256+ var valuesFn = $parse ( match [ 8 ] ) ;
241257
242258 var locals = { } ;
243259 var getLocals = keyName ? function ( value , key ) {
@@ -250,11 +266,12 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
250266 } ;
251267
252268
253- function Option ( selectValue , viewValue , label , group ) {
269+ function Option ( selectValue , viewValue , label , group , disabled ) {
254270 this . selectValue = selectValue ;
255271 this . viewValue = viewValue ;
256272 this . label = label ;
257273 this . group = group ;
274+ this . disabled = disabled ;
258275 }
259276
260277 return {
@@ -269,8 +286,10 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
269286 var locals = getLocals ( values [ key ] , key ) ;
270287 var label = displayFn ( scope , locals ) ;
271288 var selectValue = getTrackByValue ( values [ key ] , locals ) ;
289+ var disabledBy = disableByFn ( scope , locals ) ;
272290 watchedArray . push ( selectValue ) ;
273291 watchedArray . push ( label ) ;
292+ watchedArray . push ( disabledBy ) ;
274293 } ) ;
275294 return watchedArray ;
276295 } ) ,
@@ -296,7 +315,8 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
296315 var selectValue = getTrackByValue ( viewValue , locals ) ;
297316 var label = displayFn ( scope , locals ) ;
298317 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 ) ;
300320
301321 optionItems . push ( optionItem ) ;
302322 selectValueMap [ selectValue ] = optionItem ;
@@ -322,7 +342,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
322342 return {
323343 restrict : 'A' ,
324344 terminal : true ,
325- require : [ 'select' , '? ngModel' ] ,
345+ require : [ 'select' , 'ngModel' ] ,
326346 link : function ( scope , selectElement , attr , ctrls ) {
327347
328348 // if ngModel is not defined, we don't need to do anything
@@ -373,7 +393,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
373393 selectCtrl . writeValue = function writeNgOptionsValue ( value ) {
374394 var option = options . getOptionFromViewValue ( value ) ;
375395
376- if ( option ) {
396+ if ( option && ! option . disabled ) {
377397 if ( selectElement [ 0 ] . value !== option . selectValue ) {
378398 removeUnknownOption ( ) ;
379399 removeEmptyOption ( ) ;
@@ -397,7 +417,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
397417
398418 var selectedOption = options . selectValueMap [ selectElement . val ( ) ] ;
399419
400- if ( selectedOption ) {
420+ if ( selectedOption && ! selectedOption . disabled ) {
401421 removeEmptyOption ( ) ;
402422 removeUnknownOption ( ) ;
403423 return selectedOption . viewValue ;
@@ -422,18 +442,22 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
422442 if ( value ) {
423443 value . forEach ( function ( item ) {
424444 var option = options . getOptionFromViewValue ( item ) ;
425- if ( option ) option . element . selected = true ;
445+ if ( option && ! option . disabled ) option . element . selected = true ;
426446 } ) ;
427447 }
428448 } ;
429449
430450
431451 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 ) ;
436458 } ) ;
459+
460+ return selections ;
437461 } ;
438462 }
439463
@@ -466,6 +490,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
466490
467491 function updateOptionElement ( option , element ) {
468492 option . element = element ;
493+ element . disabled = option . disabled ;
469494 if ( option . value !== element . value ) element . value = option . selectValue ;
470495 if ( option . label !== element . label ) {
471496 element . label = option . label ;
0 commit comments