1
1
import {
2
- Directive ,
3
- ElementRef ,
4
- forwardRef ,
5
- Host ,
6
- Input ,
7
- NgZone ,
8
- Optional ,
9
- OnDestroy ,
10
- ViewContainerRef ,
2
+ Directive ,
3
+ ElementRef ,
4
+ forwardRef ,
5
+ Host ,
6
+ Input ,
7
+ NgZone ,
8
+ Optional ,
9
+ OnDestroy ,
10
+ ViewContainerRef ,
11
+ Renderer ,
11
12
} from '@angular/core' ;
12
13
import { ControlValueAccessor , NG_VALUE_ACCESSOR } from '@angular/forms' ;
13
14
import { Overlay , OverlayRef , OverlayState , TemplatePortal } from '../core' ;
@@ -58,8 +59,8 @@ export const MD_AUTOCOMPLETE_VALUE_ACCESSOR: any = {
58
59
'[attr.aria-expanded]' : 'panelOpen.toString()' ,
59
60
'[attr.aria-owns]' : 'autocomplete?.id' ,
60
61
'(focus)' : 'openPanel()' ,
61
- '(blur)' : '_handleBlur($event.relatedTarget?.tagName)' ,
62
62
'(input)' : '_handleInput($event)' ,
63
+ '(blur)' : '_onTouched()' ,
63
64
'(keydown)' : '_handleKeydown($event)' ,
64
65
} ,
65
66
providers : [ MD_AUTOCOMPLETE_VALUE_ACCESSOR ]
@@ -74,12 +75,15 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
74
75
75
76
private _positionStrategy : ConnectedPositionStrategy ;
76
77
77
- /** Stream of blur events that should close the panel. */
78
- private _blurStream = new Subject < any > ( ) ;
78
+ /** Stream of click events that should close the panel. */
79
+ private _outsideClickStream = new Subject < any > ( ) ;
79
80
80
81
/** Whether or not the placeholder state is being overridden. */
81
82
private _manuallyFloatingPlaceholder = false ;
82
83
84
+ /** Keeps track of the function that allows us to remove the `document` click listener. */
85
+ private _unbindGlobalListener : Function ;
86
+
83
87
/** View -> model callback called when value changes */
84
88
_onChange = ( value : any ) => { } ;
85
89
@@ -100,7 +104,7 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
100
104
}
101
105
102
106
constructor ( private _element : ElementRef , private _overlay : Overlay ,
103
- private _viewContainerRef : ViewContainerRef ,
107
+ private _renderer : Renderer , private _viewContainerRef : ViewContainerRef ,
104
108
@Optional ( ) private _dir : Dir , private _zone : NgZone ,
105
109
@Optional ( ) @Host ( ) private _inputContainer : MdInputContainer ) { }
106
110
@@ -133,6 +137,16 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
133
137
134
138
this . _panelOpen = true ;
135
139
this . _floatPlaceholder ( ) ;
140
+
141
+ if ( ! this . _unbindGlobalListener ) {
142
+ this . _unbindGlobalListener = this . _renderer . listenGlobal ( 'document' , 'click' ,
143
+ ( event : MouseEvent ) => {
144
+ if ( ! this . _inputContainer . _elementRef . nativeElement . contains ( event . target ) &&
145
+ ! this . _overlayRef . overlayElement . contains ( event . target as HTMLElement ) ) {
146
+ this . _outsideClickStream . next ( null ) ;
147
+ }
148
+ } ) ;
149
+ }
136
150
}
137
151
138
152
/** Closes the autocomplete suggestion panel. */
@@ -143,6 +157,11 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
143
157
144
158
this . _panelOpen = false ;
145
159
this . _resetPlaceholder ( ) ;
160
+
161
+ if ( this . _unbindGlobalListener ) {
162
+ this . _unbindGlobalListener ( ) ;
163
+ this . _unbindGlobalListener = null ;
164
+ }
146
165
}
147
166
148
167
/**
@@ -151,9 +170,9 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
151
170
*/
152
171
get panelClosingActions ( ) : Observable < MdOptionSelectionChange > {
153
172
return Observable . merge (
154
- this . optionSelections ,
155
- this . _blurStream . asObservable ( ) ,
156
- this . autocomplete . _keyManager . tabOut
173
+ this . optionSelections ,
174
+ this . autocomplete . _keyManager . tabOut ,
175
+ this . _outsideClickStream
157
176
) ;
158
177
}
159
178
@@ -223,15 +242,6 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
223
242
}
224
243
}
225
244
226
- _handleBlur ( newlyFocusedTag : string ) : void {
227
- this . _onTouched ( ) ;
228
-
229
- // Only emit blur event if the new focus is *not* on an option.
230
- if ( newlyFocusedTag !== 'MD-OPTION' ) {
231
- this . _blurStream . next ( null ) ;
232
- }
233
- }
234
-
235
245
/**
236
246
* In "auto" mode, the placeholder will animate down as soon as focus is lost.
237
247
* This causes the value to jump when selecting an option with the mouse.
@@ -304,8 +314,8 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
304
314
* control to that value. It will also mark the control as dirty if this interaction
305
315
* stemmed from the user.
306
316
*/
307
- private _setValueAndClose ( event : MdOptionSelectionChange | null ) : void {
308
- if ( event ) {
317
+ private _setValueAndClose ( event : MdOptionSelectEvent | null ) : void {
318
+ if ( event && event . source ) {
309
319
this . _setTriggerValue ( event . source . value ) ;
310
320
this . _onChange ( event . source . value ) ;
311
321
}
0 commit comments