4
4
5
5
var noopNgModelController = { $setViewValue : noop , $render : noop } ;
6
6
7
+ function setOptionSelectedStatus ( optionEl , value ) {
8
+ optionEl . prop ( 'selected' , value ) ; // needed for IE
9
+ /**
10
+ * When unselecting an option, setting the property to null / false should be enough
11
+ * However, screenreaders might react to the selected attribute instead, see
12
+ * https://github.com/angular/angular.js/issues/14419
13
+ * Note: "selected" is a boolean attr and will be removed when the "value" arg in attr() is false
14
+ * or null
15
+ */
16
+ optionEl . attr ( 'selected' , value ) ;
17
+ }
18
+
7
19
/**
8
20
* @ngdoc type
9
21
* @name select.SelectController
@@ -44,14 +56,14 @@ var SelectController =
44
56
var unknownVal = self . generateUnknownOptionValue ( val ) ;
45
57
self . unknownOption . val ( unknownVal ) ;
46
58
$element . prepend ( self . unknownOption ) ;
47
- setOptionAsSelected ( self . unknownOption ) ;
59
+ setOptionSelectedStatus ( self . unknownOption , true ) ;
48
60
$element . val ( unknownVal ) ;
49
61
} ;
50
62
51
63
self . updateUnknownOption = function ( val ) {
52
64
var unknownVal = self . generateUnknownOptionValue ( val ) ;
53
65
self . unknownOption . val ( unknownVal ) ;
54
- setOptionAsSelected ( self . unknownOption ) ;
66
+ setOptionSelectedStatus ( self . unknownOption , true ) ;
55
67
$element . val ( unknownVal ) ;
56
68
} ;
57
69
@@ -66,7 +78,7 @@ var SelectController =
66
78
self . selectEmptyOption = function ( ) {
67
79
if ( self . emptyOption ) {
68
80
$element . val ( '' ) ;
69
- setOptionAsSelected ( self . emptyOption ) ;
81
+ setOptionSelectedStatus ( self . emptyOption , true ) ;
70
82
}
71
83
} ;
72
84
@@ -102,7 +114,7 @@ var SelectController =
102
114
// Make sure to remove the selected attribute from the previously selected option
103
115
// Otherwise, screen readers might get confused
104
116
var currentlySelectedOption = $element [ 0 ] . options [ $element [ 0 ] . selectedIndex ] ;
105
- if ( currentlySelectedOption ) currentlySelectedOption . removeAttribute ( 'selected' ) ;
117
+ if ( currentlySelectedOption ) setOptionSelectedStatus ( jqLite ( currentlySelectedOption ) , false ) ;
106
118
107
119
if ( self . hasOption ( value ) ) {
108
120
self . removeUnknownOption ( ) ;
@@ -112,7 +124,7 @@ var SelectController =
112
124
113
125
// Set selected attribute and property on selected option for screen readers
114
126
var selectedOption = $element [ 0 ] . options [ $element [ 0 ] . selectedIndex ] ;
115
- setOptionAsSelected ( jqLite ( selectedOption ) ) ;
127
+ setOptionSelectedStatus ( jqLite ( selectedOption ) , true ) ;
116
128
} else {
117
129
if ( value == null && self . emptyOption ) {
118
130
self . removeUnknownOption ( ) ;
@@ -292,11 +304,6 @@ var SelectController =
292
304
}
293
305
} ) ;
294
306
} ;
295
-
296
- function setOptionAsSelected ( optionEl ) {
297
- optionEl . prop ( 'selected' , true ) ; // needed for IE
298
- optionEl . attr ( 'selected' , true ) ;
299
- }
300
307
} ] ;
301
308
302
309
/**
@@ -611,11 +618,14 @@ var selectDirective = function() {
611
618
includes ( value , selectCtrl . selectValueMap [ option . value ] ) ) ;
612
619
var currentlySelected = option . selected ;
613
620
614
- // IE and Edge will de-select selected options when you set the selected property again, e.g.
615
- // when you add to the selection via shift+click/UP/DOWN
616
- // Therefore, only set it if necessary
617
- if ( ( shouldBeSelected && ! currentlySelected ) || ( ! shouldBeSelected && currentlySelected ) ) {
618
- option . selected = shouldBeSelected ;
621
+ // IE and Edge, adding options to the selection via shift+click/UP/DOWN,
622
+ // will de-select already selected options if "selected" on those options was set
623
+ // more than once (i.e. when the options were already selected)
624
+ // So we only modify the selected property if neccessary.
625
+ // Note: this behavior cannot be replicated via unit tests because it only shows in the
626
+ // actual user interface.
627
+ if ( shouldBeSelected !== currentlySelected ) {
628
+ setOptionSelectedStatus ( jqLite ( option ) , shouldBeSelected ) ;
619
629
}
620
630
621
631
} ) ;
0 commit comments