@@ -69,15 +69,25 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
6969
7070 var hasFocus ;
7171
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+
7279 // WAI-ARIA
80+ var popupId = 'typeahead-' + scope . $id + '-' + Math . floor ( Math . random ( ) * 10000 ) ;
7381 element . attr ( {
7482 'aria-autocomplete' : 'list' ,
75- 'aria-expanded' : false
83+ 'aria-expanded' : false ,
84+ 'aria-owns' : popupId
7685 } ) ;
7786
7887 //pop-up element used to display matches
7988 var popUpEl = angular . element ( '<div typeahead-popup></div>' ) ;
8089 popUpEl . attr ( {
90+ id : popupId ,
8191 matches : 'matches' ,
8292 active : 'activeIdx' ,
8393 select : 'select(activeIdx)' ,
@@ -89,19 +99,26 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
8999 popUpEl . attr ( 'template-url' , attrs . typeaheadTemplateUrl ) ;
90100 }
91101
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-
99102 var resetMatches = function ( ) {
100103 scope . matches = [ ] ;
101104 scope . activeIdx = - 1 ;
102105 element . attr ( 'aria-expanded' , false ) ;
103106 } ;
104107
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+
105122 var getMatchesAsync = function ( inputValue ) {
106123
107124 var locals = { $viewValue : inputValue } ;
@@ -121,6 +138,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
121138 for ( var i = 0 ; i < matches . length ; i ++ ) {
122139 locals [ parserResult . itemName ] = matches [ i ] ;
123140 scope . matches . push ( {
141+ id : getMatchId ( i ) ,
124142 label : parserResult . viewMapper ( scope , locals ) ,
125143 model : matches [ i ]
126144 } ) ;
0 commit comments