11import {
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 ,
1112} from '@angular/core' ;
1213import { ControlValueAccessor , NG_VALUE_ACCESSOR } from '@angular/forms' ;
1314import { Overlay , OverlayRef , OverlayState , TemplatePortal } from '../core' ;
@@ -58,8 +59,8 @@ export const MD_AUTOCOMPLETE_VALUE_ACCESSOR: any = {
5859 '[attr.aria-expanded]' : 'panelOpen.toString()' ,
5960 '[attr.aria-owns]' : 'autocomplete?.id' ,
6061 '(focus)' : 'openPanel()' ,
61- '(blur)' : '_handleBlur($event.relatedTarget?.tagName)' ,
6262 '(input)' : '_handleInput($event)' ,
63+ '(blur)' : '_onTouched()' ,
6364 '(keydown)' : '_handleKeydown($event)' ,
6465 } ,
6566 providers : [ MD_AUTOCOMPLETE_VALUE_ACCESSOR ]
@@ -74,12 +75,15 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
7475
7576 private _positionStrategy : ConnectedPositionStrategy ;
7677
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 > ( ) ;
7980
8081 /** Whether or not the placeholder state is being overridden. */
8182 private _manuallyFloatingPlaceholder = false ;
8283
84+ /** Keeps track of the function that allows us to remove the `document` click listener. */
85+ private _unbindGlobalListener : Function ;
86+
8387 /** View -> model callback called when value changes */
8488 _onChange = ( value : any ) => { } ;
8589
@@ -100,7 +104,7 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
100104 }
101105
102106 constructor ( private _element : ElementRef , private _overlay : Overlay ,
103- private _viewContainerRef : ViewContainerRef ,
107+ private _renderer : Renderer , private _viewContainerRef : ViewContainerRef ,
104108 @Optional ( ) private _dir : Dir , private _zone : NgZone ,
105109 @Optional ( ) @Host ( ) private _inputContainer : MdInputContainer ) { }
106110
@@ -133,6 +137,16 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
133137
134138 this . _panelOpen = true ;
135139 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+ }
136150 }
137151
138152 /** Closes the autocomplete suggestion panel. */
@@ -143,6 +157,11 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
143157
144158 this . _panelOpen = false ;
145159 this . _resetPlaceholder ( ) ;
160+
161+ if ( this . _unbindGlobalListener ) {
162+ this . _unbindGlobalListener ( ) ;
163+ this . _unbindGlobalListener = null ;
164+ }
146165 }
147166
148167 /**
@@ -151,9 +170,9 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
151170 */
152171 get panelClosingActions ( ) : Observable < MdOptionSelectionChange > {
153172 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
157176 ) ;
158177 }
159178
@@ -223,15 +242,6 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
223242 }
224243 }
225244
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-
235245 /**
236246 * In "auto" mode, the placeholder will animate down as soon as focus is lost.
237247 * This causes the value to jump when selecting an option with the mouse.
@@ -304,8 +314,8 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
304314 * control to that value. It will also mark the control as dirty if this interaction
305315 * stemmed from the user.
306316 */
307- private _setValueAndClose ( event : MdOptionSelectionChange | null ) : void {
308- if ( event ) {
317+ private _setValueAndClose ( event : MdOptionSelectEvent | null ) : void {
318+ if ( event && event . source ) {
309319 this . _setTriggerValue ( event . source . value ) ;
310320 this . _onChange ( event . source . value ) ;
311321 }
0 commit comments