@@ -4,8 +4,10 @@ import {
4
4
ElementRef ,
5
5
forwardRef ,
6
6
Input ,
7
+ NgZone ,
7
8
Optional ,
8
9
OnDestroy ,
10
+ QueryList ,
9
11
ViewContainerRef ,
10
12
} from '@angular/core' ;
11
13
import { ControlValueAccessor , NG_VALUE_ACCESSOR } from '@angular/forms' ;
@@ -18,6 +20,7 @@ import {MdOptionSelectEvent, MdOption} from '../core/option/option';
18
20
import { ActiveDescendantKeyManager } from '../core/a11y/activedescendant-key-manager' ;
19
21
import { ENTER , UP_ARROW , DOWN_ARROW } from '../core/keyboard/keycodes' ;
20
22
import { Subscription } from 'rxjs/Subscription' ;
23
+ import 'rxjs/add/observable/of' ;
21
24
import 'rxjs/add/observable/merge' ;
22
25
import { Dir } from '../core/rtl/dir' ;
23
26
import 'rxjs/add/operator/startWith' ;
@@ -57,7 +60,7 @@ export const MD_AUTOCOMPLETE_VALUE_ACCESSOR: any = {
57
60
'[attr.aria-owns]' : 'autocomplete?.id' ,
58
61
'(focus)' : 'openPanel()' ,
59
62
'(blur)' : '_onTouched()' ,
60
- '(input)' : '_onChange ($event.target.value)' ,
63
+ '(input)' : '_handleInput ($event.target.value)' ,
61
64
'(keydown)' : '_handleKeydown($event)' ,
62
65
} ,
63
66
providers : [ MD_AUTOCOMPLETE_VALUE_ACCESSOR ]
@@ -85,7 +88,7 @@ export class MdAutocompleteTrigger implements AfterContentInit, ControlValueAcce
85
88
86
89
constructor ( private _element : ElementRef , private _overlay : Overlay ,
87
90
private _viewContainerRef : ViewContainerRef ,
88
- @Optional ( ) private _dir : Dir ) { }
91
+ @Optional ( ) private _dir : Dir , private _zone : NgZone ) { }
89
92
90
93
ngAfterContentInit ( ) {
91
94
this . _keyManager = new ActiveDescendantKeyManager ( this . autocomplete . options ) . withWrap ( ) ;
@@ -131,7 +134,7 @@ export class MdAutocompleteTrigger implements AfterContentInit, ControlValueAcce
131
134
* A stream of actions that should close the autocomplete panel, including
132
135
* when an option is selected and when the backdrop is clicked.
133
136
*/
134
- get panelClosingActions ( ) : Observable < any > {
137
+ get panelClosingActions ( ) : Observable < MdOptionSelectEvent | null > {
135
138
return Observable . merge (
136
139
...this . optionSelections ,
137
140
this . _overlayRef . backdropClick ( ) ,
@@ -140,7 +143,7 @@ export class MdAutocompleteTrigger implements AfterContentInit, ControlValueAcce
140
143
}
141
144
142
145
/** Stream of autocomplete option selections. */
143
- get optionSelections ( ) : Observable < any > [ ] {
146
+ get optionSelections ( ) : Observable < MdOptionSelectEvent > [ ] {
144
147
return this . autocomplete . options . map ( option => option . onSelect ) ;
145
148
}
146
149
@@ -149,6 +152,11 @@ export class MdAutocompleteTrigger implements AfterContentInit, ControlValueAcce
149
152
return this . _keyManager . activeItem as MdOption ;
150
153
}
151
154
155
+ /** The initial list of autocomplete options, as soon as the zone has stabilized */
156
+ get initialOptionList ( ) : Observable < QueryList < MdOption > > {
157
+ return this . _zone . onStable . first ( ) . map ( ( ) => this . autocomplete . options ) ;
158
+ }
159
+
152
160
/**
153
161
* Sets the autocomplete's value. Part of the ControlValueAccessor interface
154
162
* required to integrate with Angular's core forms API.
@@ -185,14 +193,19 @@ export class MdAutocompleteTrigger implements AfterContentInit, ControlValueAcce
185
193
if ( this . activeOption && event . keyCode === ENTER ) {
186
194
this . activeOption . _selectViaInteraction ( ) ;
187
195
} else {
188
- this . openPanel ( ) ;
189
196
this . _keyManager . onKeydown ( event ) ;
190
197
if ( event . keyCode === UP_ARROW || event . keyCode === DOWN_ARROW ) {
198
+ this . openPanel ( ) ;
191
199
this . _scrollToOption ( ) ;
192
200
}
193
201
}
194
202
}
195
203
204
+ _handleInput ( value : string ) : void {
205
+ this . _onChange ( value ) ;
206
+ this . openPanel ( ) ;
207
+ }
208
+
196
209
/**
197
210
* Given that we are not actually focusing active options, we must manually adjust scroll
198
211
* to reveal options below the fold. First, we find the offset of the option from the top
@@ -211,15 +224,15 @@ export class MdAutocompleteTrigger implements AfterContentInit, ControlValueAcce
211
224
* stream every time the option list changes.
212
225
*/
213
226
private _subscribeToClosingActions ( ) : void {
214
- // Every time the option list changes...
215
- this . autocomplete . options . changes
216
- // and also at initialization, before there are any option changes...
217
- . startWith ( null )
227
+ // When the zone is stable initially, and when the option list changes...
228
+ Observable . merge ( this . initialOptionList , this . autocomplete . options . changes )
218
229
// create a new stream of panelClosingActions, replacing any previous streams
219
230
// that were created, and flatten it so our stream only emits closing events...
220
- . switchMap ( ( ) => {
231
+ . switchMap ( options => {
221
232
this . _resetPanel ( ) ;
222
- return this . panelClosingActions ;
233
+ // If the options list is empty, emit close event immediately.
234
+ // Otherwise, listen for panel closing actions...
235
+ return options . length ? this . panelClosingActions : Observable . of ( null ) ;
223
236
} )
224
237
// when the first closing event occurs...
225
238
. first ( )
0 commit comments