@@ -14,12 +14,15 @@ var SelectController =
14
14
[ '$element' , '$scope' , function ( $element , $scope ) {
15
15
16
16
var self = this ,
17
- optionsMap = new HashMap ( ) ;
17
+ optionsMap = new HashMap ( ) ,
18
+ handleMultipleDestroy = false ; // Flag to run an update to the model after selected options
19
+ // in a multiple select have been destroyed
18
20
19
21
self . selectValueMap = { } ; // Keys are the hashed values, values the original values
20
22
21
23
// If the ngModel doesn't get provided then provide a dummy noop version to prevent errors
22
24
self . ngModelCtrl = noopNgModelController ;
25
+ self . multiple = false ;
23
26
24
27
// The "unknown" option is one that is prepended to the list if the viewValue
25
28
// does not match any of the options. When it is rendered the value of the unknown
@@ -54,8 +57,6 @@ var SelectController =
54
57
55
58
console . log ( 'read' , 'elval' , val , 'possiblyhashed' , realVal )
56
59
if ( self . hasOption ( realVal ) ) {
57
- console . log ( 'has selected val' , realVal )
58
- // self.removeUnknownOption();
59
60
return realVal ;
60
61
}
61
62
@@ -66,7 +67,7 @@ var SelectController =
66
67
// Write the value to the select control, the implementation of this changes depending
67
68
// upon whether the select can have multiple values and whether ngOptions is at work.
68
69
self . writeValue = function writeSingleValue ( value ) {
69
- console . log ( 'write' , value ) ;
70
+ console . log ( 'write' , value , 'hasOption' , self . hasOption ( value ) ) ;
70
71
if ( self . hasOption ( value ) ) {
71
72
console . log ( 'hasOption' , value ) ;
72
73
self . removeUnknownOption ( ) ;
@@ -131,10 +132,26 @@ var SelectController =
131
132
return ! ! optionsMap . get ( value ) ;
132
133
} ;
133
134
135
+ var handleMultipleChanges = false ;
136
+ function updateModelAfterOptionChange ( renderAfter ) {
137
+ if ( self . multiple ) {
138
+ if ( ! handleMultipleChanges ) {
139
+ handleMultipleChanges = true ;
140
+ } else {
141
+ $scope . $$postDigest ( function ( ) {
142
+ handleMultipleChanges = false ;
143
+ self . ngModelCtrl . $setViewValue ( self . readValue ( ) ) ;
144
+ if ( renderAfter ) self . ngModelCtrl . $render ( ) ;
145
+ } ) ;
146
+ }
147
+ } else {
148
+ self . ngModelCtrl . $setViewValue ( self . readValue ( ) ) ;
149
+ }
150
+ }
151
+
134
152
135
153
self . registerOption = function ( optionScope , optionElement , optionAttrs , interpolateValueFn , interpolateTextFn ) {
136
154
137
- // console.log('attr', optionAttrs)
138
155
if ( optionAttrs . $attr . ngValue ) {
139
156
// The value attribute is set by ngValue
140
157
var oldVal , hashedVal = NaN ;
@@ -164,9 +181,8 @@ var SelectController =
164
181
console . log ( 'previouslySelected' , previouslySelected , 'removal' , removal )
165
182
166
183
if ( removal && previouslySelected ) {
167
- console . log ( 'removed val is currently selected' , $element . val ( ) )
168
- self . ngModelCtrl . $setViewValue ( self . readValue ( ) ) ;
169
- }
184
+ updateModelAfterOptionChange ( ) ;
185
+ }
170
186
171
187
} ) ;
172
188
} else if ( interpolateValueFn ) {
@@ -189,8 +205,8 @@ var SelectController =
189
205
console . log ( 'updated interpolated value' , 'new' , newVal , 'removed' , removedVal , 'current' , currentVal ) ;
190
206
if ( removal && previouslySelected ) {
191
207
console . log ( 'removed val is currently selected' , $element . val ( ) )
192
- self . ngModelCtrl . $setViewValue ( self . readValue ( ) ) ;
193
- }
208
+ updateModelAfterOptionChange ( ) ;
209
+ }
194
210
} ) ;
195
211
} else if ( interpolateTextFn ) {
196
212
// The text content is interpolated
@@ -203,7 +219,7 @@ var SelectController =
203
219
self . addOption ( newVal , optionElement ) ;
204
220
205
221
if ( oldVal && previouslySelected ) {
206
- self . ngModelCtrl . $setViewValue ( self . readValue ( ) ) ;
222
+ updateModelAfterOptionChange ( ) ;
207
223
}
208
224
} ) ;
209
225
} else {
@@ -220,10 +236,17 @@ var SelectController =
220
236
221
237
if ( newVal === 'true' || newVal && optionElement . prop ( 'selected' ) ) {
222
238
console . log ( 'disabled' )
223
- self . ngModelCtrl . $setViewValue ( null ) ;
224
- self . ngModelCtrl . $render ( ) ;
239
+
240
+ if ( self . multiple ) {
241
+ updateModelAfterOptionChange ( true ) ;
242
+ } else {
243
+ self . ngModelCtrl . $setViewValue ( null ) ;
244
+ self . ngModelCtrl . $render ( ) ;
245
+ }
225
246
oldDisabled = newVal ;
226
- } else if ( isDefined ( oldDisabled ) && ! newVal || newVal === 'false' ) {
247
+ }
248
+
249
+ // else if (isDefined(oldDisabled) && !newVal || newVal === 'false') {
227
250
// var val = optionAttrs.value;
228
251
// console.log('OA', optionAttrs.value);
229
252
// var realVal = val in self.selectValueMap ? self.selectValueMap[val] : val;
@@ -233,21 +256,24 @@ var SelectController =
233
256
// self.writeValue(realVal);
234
257
// self.ngModelCtrl.$setViewValue(self.readValue());
235
258
// }
236
- }
259
+ // }
237
260
} ) ;
238
261
239
262
optionElement . on ( '$destroy' , function ( ) {
240
263
var currentValue = self . readValue ( ) ;
241
264
var removeValue = optionAttrs . value ;
242
265
243
- console . log ( 'destroy' , removeValue , 'elval' , $element . val ( ) )
266
+ console . log ( 'destroy' , 'removed' , removeValue , 'elval' , $element . val ( ) )
244
267
// console.log('viewValue', self.ngModelCtrl.$viewValue)
245
268
self . removeOption ( removeValue ) ;
246
269
self . ngModelCtrl . $render ( ) ;
247
270
248
- if ( currentValue === removeValue ) {
249
- // console.log('removed val is currently selected', $element.val())
250
- // console.log('self.readValue()', self.readValue());
271
+ if ( self . multiple && currentValue && currentValue . indexOf ( removeValue ) !== - 1 ) {
272
+ // When multiple (selected) options are destroyed at the same time, we don't want
273
+ // to run a model update for each of them. Instead, run a single update in the $$postDigest
274
+ // NOTE: Will that interfere with the regular model update?
275
+ updateModelAfterOptionChange ( ) ;
276
+ } else if ( currentValue === removeValue ) {
251
277
self . ngModelCtrl . $setViewValue ( self . readValue ( ) ) ;
252
278
253
279
}
@@ -499,12 +525,14 @@ var selectDirective = function() {
499
525
// we have to add an extra watch since ngModel doesn't work well with arrays - it
500
526
// doesn't trigger rendering if only an item in the array changes.
501
527
if ( attr . multiple ) {
528
+ selectCtrl . multiple = true ;
502
529
503
530
// Read value now needs to check each option to see if it is selected
504
531
selectCtrl . readValue = function readMultipleValue ( ) {
505
532
var array = [ ] ;
506
533
forEach ( element . find ( 'option' ) , function ( option ) {
507
- if ( option . selected ) {
534
+ // console.log('read m o', option);
535
+ if ( option . selected && ! option . disabled ) {
508
536
var val = option . value ;
509
537
array . push ( val in selectCtrl . selectValueMap ? selectCtrl . selectValueMap [ val ] : val ) ;
510
538
}
0 commit comments