@@ -69,15 +69,25 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
69
69
70
70
var hasFocus ;
71
71
72
+ //create a child scope for the typeahead directive so we are not polluting original scope
73
+ //with typeahead-specific data (matches, query etc.)
74
+ var scope = originalScope . $new ( ) ;
75
+ originalScope . $on ( '$destroy' , function ( ) {
76
+ scope . $destroy ( ) ;
77
+ } ) ;
78
+
72
79
// WAI-ARIA
80
+ var popupId = 'typeahead-' + scope . $id + '-' + Math . floor ( Math . random ( ) * 10000 ) ;
73
81
element . attr ( {
74
82
'aria-autocomplete' : 'list' ,
75
- 'aria-expanded' : false
83
+ 'aria-expanded' : false ,
84
+ 'aria-owns' : popupId
76
85
} ) ;
77
86
78
87
//pop-up element used to display matches
79
88
var popUpEl = angular . element ( '<div typeahead-popup></div>' ) ;
80
89
popUpEl . attr ( {
90
+ id : popupId ,
81
91
matches : 'matches' ,
82
92
active : 'activeIdx' ,
83
93
select : 'select(activeIdx)' ,
@@ -89,19 +99,26 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
89
99
popUpEl . attr ( 'template-url' , attrs . typeaheadTemplateUrl ) ;
90
100
}
91
101
92
- //create a child scope for the typeahead directive so we are not polluting original scope
93
- //with typeahead-specific data (matches, query etc.)
94
- var scope = originalScope . $new ( ) ;
95
- originalScope . $on ( '$destroy' , function ( ) {
96
- scope . $destroy ( ) ;
97
- } ) ;
98
-
99
102
var resetMatches = function ( ) {
100
103
scope . matches = [ ] ;
101
104
scope . activeIdx = - 1 ;
102
105
element . attr ( 'aria-expanded' , false ) ;
103
106
} ;
104
107
108
+ var getMatchId = function ( index ) {
109
+ return popupId + '-option-' + index ;
110
+ } ;
111
+
112
+ // Indicate that the specified match is the active (pre-selected) item in the list owned by this typeahead.
113
+ // This attribute is added or removed automatically when the `activeIdx` changes.
114
+ scope . $watch ( 'activeIdx' , function ( index ) {
115
+ if ( index < 0 ) {
116
+ element . removeAttr ( 'aria-activedescendant' ) ;
117
+ } else {
118
+ element . attr ( 'aria-activedescendant' , getMatchId ( index ) ) ;
119
+ }
120
+ } ) ;
121
+
105
122
var getMatchesAsync = function ( inputValue ) {
106
123
107
124
var locals = { $viewValue : inputValue } ;
@@ -121,6 +138,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
121
138
for ( var i = 0 ; i < matches . length ; i ++ ) {
122
139
locals [ parserResult . itemName ] = matches [ i ] ;
123
140
scope . matches . push ( {
141
+ id : getMatchId ( i ) ,
124
142
label : parserResult . viewMapper ( scope , locals ) ,
125
143
model : matches [ i ]
126
144
} ) ;
0 commit comments