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 ,
12
+ Inject ,
13
+ ChangeDetectorRef ,
11
14
} from '@angular/core' ;
12
15
import { ControlValueAccessor , NG_VALUE_ACCESSOR } from '@angular/forms' ;
16
+ import { DOCUMENT } from '@angular/platform-browser' ;
13
17
import { Overlay , OverlayRef , OverlayState , TemplatePortal } from '../core' ;
14
18
import { MdAutocomplete } from './autocomplete' ;
15
19
import { PositionStrategy } from '../core/overlay/position/position-strategy' ;
@@ -18,12 +22,13 @@ import {Observable} from 'rxjs/Observable';
18
22
import { MdOptionSelectionChange , MdOption } from '../core/option/option' ;
19
23
import { ENTER , UP_ARROW , DOWN_ARROW } from '../core/keyboard/keycodes' ;
20
24
import { Dir } from '../core/rtl/dir' ;
25
+ import { MdInputContainer } from '../input/input-container' ;
21
26
import { Subscription } from 'rxjs/Subscription' ;
22
- import { Subject } from 'rxjs/Subject' ;
23
27
import 'rxjs/add/observable/merge' ;
28
+ import 'rxjs/add/observable/fromEvent' ;
29
+ import 'rxjs/add/operator/filter' ;
24
30
import 'rxjs/add/operator/startWith' ;
25
31
import 'rxjs/add/operator/switchMap' ;
26
- import { MdInputContainer } from '../input/input-container' ;
27
32
28
33
/**
29
34
* The following style constants are necessary to save here in order
@@ -58,8 +63,8 @@ export const MD_AUTOCOMPLETE_VALUE_ACCESSOR: any = {
58
63
'[attr.aria-expanded]' : 'panelOpen.toString()' ,
59
64
'[attr.aria-owns]' : 'autocomplete?.id' ,
60
65
'(focus)' : 'openPanel()' ,
61
- '(blur)' : '_handleBlur($event.relatedTarget?.tagName)' ,
62
66
'(input)' : '_handleInput($event)' ,
67
+ '(blur)' : '_onTouched()' ,
63
68
'(keydown)' : '_handleKeydown($event)' ,
64
69
} ,
65
70
providers : [ MD_AUTOCOMPLETE_VALUE_ACCESSOR ]
@@ -74,9 +79,6 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
74
79
75
80
private _positionStrategy : ConnectedPositionStrategy ;
76
81
77
- /** Stream of blur events that should close the panel. */
78
- private _blurStream = new Subject < any > ( ) ;
79
-
80
82
/** Whether or not the placeholder state is being overridden. */
81
83
private _manuallyFloatingPlaceholder = false ;
82
84
@@ -100,9 +102,11 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
100
102
}
101
103
102
104
constructor ( private _element : ElementRef , private _overlay : Overlay ,
103
- private _viewContainerRef : ViewContainerRef ,
105
+ private _renderer : Renderer , private _viewContainerRef : ViewContainerRef ,
106
+ private _changeDetectorRef : ChangeDetectorRef ,
104
107
@Optional ( ) private _dir : Dir , private _zone : NgZone ,
105
- @Optional ( ) @Host ( ) private _inputContainer : MdInputContainer ) { }
108
+ @Optional ( ) @Host ( ) private _inputContainer : MdInputContainer ,
109
+ @Optional ( ) @Inject ( DOCUMENT ) private _document : any ) { }
106
110
107
111
ngOnDestroy ( ) {
108
112
if ( this . _panelPositionSubscription ) {
@@ -144,6 +148,7 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
144
148
145
149
this . _panelOpen = false ;
146
150
this . _resetPlaceholder ( ) ;
151
+ this . _changeDetectorRef . detectChanges ( ) ;
147
152
}
148
153
149
154
/**
@@ -152,9 +157,9 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
152
157
*/
153
158
get panelClosingActions ( ) : Observable < MdOptionSelectionChange > {
154
159
return Observable . merge (
155
- this . optionSelections ,
156
- this . _blurStream . asObservable ( ) ,
157
- this . autocomplete . _keyManager . tabOut
160
+ this . optionSelections ,
161
+ this . autocomplete . _keyManager . tabOut ,
162
+ this . outsideClickStream
158
163
) ;
159
164
}
160
165
@@ -170,6 +175,17 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
170
175
}
171
176
}
172
177
178
+ get outsideClickStream ( ) : Observable < any > {
179
+ if ( this . _document ) {
180
+ return Observable . fromEvent ( this . _document , 'click' ) . filter ( ( event : MouseEvent ) => {
181
+ let clickTarget = event . target as HTMLElement ;
182
+ return this . _panelOpen &&
183
+ ! this . _inputContainer . _elementRef . nativeElement . contains ( clickTarget ) &&
184
+ ! this . _overlayRef . overlayElement . contains ( clickTarget ) ;
185
+ } ) ;
186
+ }
187
+ }
188
+
173
189
/**
174
190
* Sets the autocomplete's value. Part of the ControlValueAccessor interface
175
191
* required to integrate with Angular's core forms API.
@@ -225,15 +241,6 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
225
241
}
226
242
}
227
243
228
- _handleBlur ( newlyFocusedTag : string ) : void {
229
- this . _onTouched ( ) ;
230
-
231
- // Only emit blur event if the new focus is *not* on an option.
232
- if ( newlyFocusedTag !== 'MD-OPTION' ) {
233
- this . _blurStream . next ( null ) ;
234
- }
235
- }
236
-
237
244
/**
238
245
* In "auto" mode, the placeholder will animate down as soon as focus is lost.
239
246
* This causes the value to jump when selecting an option with the mouse.
@@ -307,7 +314,7 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
307
314
* stemmed from the user.
308
315
*/
309
316
private _setValueAndClose ( event : MdOptionSelectionChange | null ) : void {
310
- if ( event ) {
317
+ if ( event && event . source ) {
311
318
this . _clearPreviousSelectedOption ( event . source ) ;
312
319
this . _setTriggerValue ( event . source . value ) ;
313
320
this . _onChange ( event . source . value ) ;
0 commit comments