1
1
import {
2
- AfterContentInit , Directive , ElementRef , Input , ViewContainerRef , Optional , OnDestroy
2
+ AfterContentInit ,
3
+ Directive ,
4
+ ElementRef ,
5
+ forwardRef ,
6
+ Input ,
7
+ Optional ,
8
+ OnDestroy ,
9
+ ViewContainerRef ,
3
10
} from '@angular/core' ;
4
- import { NgControl } from '@angular/forms' ;
11
+ import { ControlValueAccessor , NG_VALUE_ACCESSOR } from '@angular/forms' ;
5
12
import { Overlay , OverlayRef , OverlayState , TemplatePortal } from '../core' ;
6
13
import { MdAutocomplete } from './autocomplete' ;
7
14
import { PositionStrategy } from '../core/overlay/position/position-strategy' ;
@@ -28,6 +35,16 @@ export const AUTOCOMPLETE_OPTION_HEIGHT = 48;
28
35
/** The total height of the autocomplete panel. */
29
36
export const AUTOCOMPLETE_PANEL_HEIGHT = 256 ;
30
37
38
+ /**
39
+ * Provider that allows the autocomplete to register as a ControlValueAccessor.
40
+ * @docs -private
41
+ */
42
+ export const MD_AUTOCOMPLETE_VALUE_ACCESSOR : any = {
43
+ provide : NG_VALUE_ACCESSOR ,
44
+ useExisting : forwardRef ( ( ) => MdAutocompleteTrigger ) ,
45
+ multi : true
46
+ } ;
47
+
31
48
@Directive ( {
32
49
selector : 'input[mdAutocomplete], input[matAutocomplete]' ,
33
50
host : {
@@ -39,10 +56,13 @@ export const AUTOCOMPLETE_PANEL_HEIGHT = 256;
39
56
'[attr.aria-expanded]' : 'panelOpen.toString()' ,
40
57
'[attr.aria-owns]' : 'autocomplete?.id' ,
41
58
'(focus)' : 'openPanel()' ,
59
+ '(blur)' : '_onTouched()' ,
60
+ '(input)' : '_onChange($event.target.value)' ,
42
61
'(keydown)' : '_handleKeydown($event)' ,
43
- }
62
+ } ,
63
+ providers : [ MD_AUTOCOMPLETE_VALUE_ACCESSOR ]
44
64
} )
45
- export class MdAutocompleteTrigger implements AfterContentInit , OnDestroy {
65
+ export class MdAutocompleteTrigger implements AfterContentInit , ControlValueAccessor , OnDestroy {
46
66
private _overlayRef : OverlayRef ;
47
67
private _portal : TemplatePortal ;
48
68
private _panelOpen : boolean = false ;
@@ -54,12 +74,18 @@ export class MdAutocompleteTrigger implements AfterContentInit, OnDestroy {
54
74
private _keyManager : ActiveDescendantKeyManager ;
55
75
private _positionStrategy : ConnectedPositionStrategy ;
56
76
77
+ /** View -> model callback called when value changes */
78
+ _onChange : ( value : any ) => { } ;
79
+
80
+ /** View -> model callback called when autocomplete has been touched */
81
+ _onTouched = ( ) => { } ;
82
+
57
83
/* The autocomplete panel to be attached to this trigger. */
58
84
@Input ( 'mdAutocomplete' ) autocomplete : MdAutocomplete ;
59
85
60
86
constructor ( private _element : ElementRef , private _overlay : Overlay ,
61
87
private _viewContainerRef : ViewContainerRef ,
62
- @Optional ( ) private _controlDir : NgControl , @ Optional ( ) private _dir : Dir ) { }
88
+ @Optional ( ) private _dir : Dir ) { }
63
89
64
90
ngAfterContentInit ( ) {
65
91
this . _keyManager = new ActiveDescendantKeyManager ( this . autocomplete . options ) . withWrap ( ) ;
@@ -123,6 +149,38 @@ export class MdAutocompleteTrigger implements AfterContentInit, OnDestroy {
123
149
return this . _keyManager . activeItem as MdOption ;
124
150
}
125
151
152
+ /**
153
+ * Sets the autocomplete's value. Part of the ControlValueAccessor interface
154
+ * required to integrate with Angular's core forms API.
155
+ *
156
+ * @param value New value to be written to the model.
157
+ */
158
+ writeValue ( value : any ) : void {
159
+ Promise . resolve ( null ) . then ( ( ) => this . _setTriggerValue ( value ) ) ;
160
+ }
161
+
162
+ /**
163
+ * Saves a callback function to be invoked when the autocomplete's value
164
+ * changes from user input. Part of the ControlValueAccessor interface
165
+ * required to integrate with Angular's core forms API.
166
+ *
167
+ * @param fn Callback to be triggered when the value changes.
168
+ */
169
+ registerOnChange ( fn : ( value : any ) => { } ) : void {
170
+ this . _onChange = fn ;
171
+ }
172
+
173
+ /**
174
+ * Saves a callback function to be invoked when the autocomplete is blurred
175
+ * by the user. Part of the ControlValueAccessor interface required
176
+ * to integrate with Angular's core forms API.
177
+ *
178
+ * @param fn Callback to be triggered when the component has been touched.
179
+ */
180
+ registerOnTouched ( fn : ( ) => { } ) {
181
+ this . _onTouched = fn ;
182
+ }
183
+
126
184
_handleKeydown ( event : KeyboardEvent ) : void {
127
185
if ( this . activeOption && event . keyCode === ENTER ) {
128
186
this . activeOption . _selectViaInteraction ( ) ;
@@ -178,17 +236,20 @@ export class MdAutocompleteTrigger implements AfterContentInit, OnDestroy {
178
236
}
179
237
}
180
238
239
+ private _setTriggerValue ( value : any ) : void {
240
+ this . _element . nativeElement . value =
241
+ this . autocomplete . displayWith ? this . autocomplete . displayWith ( value ) : value ;
242
+ }
243
+
181
244
/**
182
245
* This method closes the panel, and if a value is specified, also sets the associated
183
246
* control to that value. It will also mark the control as dirty if this interaction
184
247
* stemmed from the user.
185
248
*/
186
249
private _setValueAndClose ( event : MdOptionSelectEvent | null ) : void {
187
250
if ( event ) {
188
- this . _controlDir . control . setValue ( event . source . value ) ;
189
- if ( event . isUserInput ) {
190
- this . _controlDir . control . markAsDirty ( ) ;
191
- }
251
+ this . _setTriggerValue ( event . source . value ) ;
252
+ this . _onChange ( event . source . value ) ;
192
253
}
193
254
194
255
this . closePanel ( ) ;
0 commit comments