@@ -2,11 +2,12 @@ import {
2
2
NgModule ,
3
3
ModuleWithProviders ,
4
4
Directive ,
5
+ EventEmitter ,
5
6
TemplateRef ,
6
7
ViewContainerRef ,
7
- OnInit ,
8
8
Input ,
9
9
OnDestroy ,
10
+ Output ,
10
11
ElementRef
11
12
} from '@angular/core' ;
12
13
import { Overlay , OVERLAY_PROVIDERS } from './overlay' ;
@@ -15,7 +16,8 @@ import {TemplatePortal} from '../portal/portal';
15
16
import { OverlayState } from './overlay-state' ;
16
17
import { ConnectionPositionPair } from './position/connected-position' ;
17
18
import { PortalModule } from '../portal/portal-directives' ;
18
-
19
+ import { ConnectedPositionStrategy } from './position/connected-position-strategy' ;
20
+ import { Subscription } from 'rxjs/Subscription' ;
19
21
20
22
/** Default set of positions for the overlay. Follows the behavior of a dropdown. */
21
23
let defaultPositionList = [
@@ -50,15 +52,52 @@ export class OverlayOrigin {
50
52
* Directive to facilitate declarative creation of an Overlay using a ConnectedPositionStrategy.
51
53
*/
52
54
@Directive ( {
53
- selector : '[connected-overlay]'
55
+ selector : '[connected-overlay]' ,
56
+ exportAs : 'connectedOverlay'
54
57
} )
55
- export class ConnectedOverlayDirective implements OnInit , OnDestroy {
58
+ export class ConnectedOverlayDirective implements OnDestroy {
56
59
private _overlayRef : OverlayRef ;
57
60
private _templatePortal : TemplatePortal ;
61
+ private _open = false ;
62
+ private _hasBackdrop = false ;
63
+ private _backdropSubscription : Subscription ;
58
64
59
65
@Input ( ) origin : OverlayOrigin ;
60
66
@Input ( ) positions : ConnectionPositionPair [ ] ;
61
67
68
+ /** The width of the overlay panel. */
69
+ @Input ( ) width : number | string ;
70
+
71
+ /** The height of the overlay panel. */
72
+ @Input ( ) height : number | string ;
73
+
74
+ /** The custom class to be set on the backdrop element. */
75
+ @Input ( ) backdropClass : string ;
76
+
77
+ /** Whether or not the overlay should attach a backdrop. */
78
+ @Input ( )
79
+ get hasBackdrop ( ) {
80
+ return this . _hasBackdrop ;
81
+ }
82
+
83
+ // TODO: move the boolean coercion logic to a shared function in core
84
+ set hasBackdrop ( value : any ) {
85
+ this . _hasBackdrop = value != null && `${ value } ` !== 'false' ;
86
+ }
87
+
88
+ @Input ( )
89
+ get open ( ) {
90
+ return this . _open ;
91
+ }
92
+
93
+ set open ( value : boolean ) {
94
+ value ? this . _attachOverlay ( ) : this . _detachOverlay ( ) ;
95
+ this . _open = value ;
96
+ }
97
+
98
+ /** Event emitted when the backdrop is clicked. */
99
+ @Output ( ) backdropClick : EventEmitter < null > = new EventEmitter ( ) ;
100
+
62
101
// TODO(jelbourn): inputs for size, scroll behavior, animation, etc.
63
102
64
103
constructor (
@@ -68,40 +107,93 @@ export class ConnectedOverlayDirective implements OnInit, OnDestroy {
68
107
this . _templatePortal = new TemplatePortal ( templateRef , viewContainerRef ) ;
69
108
}
70
109
71
- get overlayRef ( ) {
110
+ get overlayRef ( ) : OverlayRef {
72
111
return this . _overlayRef ;
73
112
}
74
113
75
- /** TODO: internal */
76
- ngOnInit ( ) {
77
- this . _createOverlay ( ) ;
78
- }
79
-
80
114
/** TODO: internal */
81
115
ngOnDestroy ( ) {
82
116
this . _destroyOverlay ( ) ;
83
117
}
84
118
85
- /** Creates an overlay and attaches this directive's template to it. */
119
+ /** Creates an overlay */
86
120
private _createOverlay ( ) {
87
121
if ( ! this . positions || ! this . positions . length ) {
88
122
this . positions = defaultPositionList ;
89
123
}
90
124
125
+ this . _overlayRef = this . _overlay . create ( this . _buildConfig ( ) ) ;
126
+ }
127
+
128
+ /** Builds the overlay config based on the directive's inputs */
129
+ private _buildConfig ( ) : OverlayState {
91
130
let overlayConfig = new OverlayState ( ) ;
92
- overlayConfig . positionStrategy =
93
- this . _overlay . position ( ) . connectedTo (
94
- this . origin . elementRef ,
95
- { originX : this . positions [ 0 ] . overlayX , originY : this . positions [ 0 ] . originY } ,
96
- { overlayX : this . positions [ 0 ] . overlayX , overlayY : this . positions [ 0 ] . overlayY } ) ;
97
-
98
- this . _overlayRef = this . _overlay . create ( overlayConfig ) ;
99
- this . _overlayRef . attach ( this . _templatePortal ) ;
131
+
132
+ if ( this . width || this . width === 0 ) {
133
+ overlayConfig . width = this . width ;
134
+ }
135
+
136
+ if ( this . height || this . height === 0 ) {
137
+ overlayConfig . height = this . height ;
138
+ }
139
+
140
+ overlayConfig . hasBackdrop = this . hasBackdrop ;
141
+
142
+ if ( this . backdropClass ) {
143
+ overlayConfig . backdropClass = this . backdropClass ;
144
+ }
145
+
146
+ overlayConfig . positionStrategy = this . _getPosition ( ) ;
147
+
148
+ return overlayConfig ;
149
+ }
150
+
151
+ /** Returns the position of the overlay to be set on the overlay config */
152
+ private _getPosition ( ) : ConnectedPositionStrategy {
153
+ return this . _overlay . position ( ) . connectedTo (
154
+ this . origin . elementRef ,
155
+ { originX : this . positions [ 0 ] . overlayX , originY : this . positions [ 0 ] . originY } ,
156
+ { overlayX : this . positions [ 0 ] . overlayX , overlayY : this . positions [ 0 ] . overlayY } ) ;
157
+ }
158
+
159
+ /** Attaches the overlay and subscribes to backdrop clicks if backdrop exists */
160
+ private _attachOverlay ( ) {
161
+ if ( ! this . _overlayRef ) {
162
+ this . _createOverlay ( ) ;
163
+ }
164
+
165
+ if ( ! this . _overlayRef . hasAttached ( ) ) {
166
+ this . _overlayRef . attach ( this . _templatePortal ) ;
167
+ }
168
+
169
+ if ( this . hasBackdrop ) {
170
+ this . _backdropSubscription = this . _overlayRef . backdropClick ( ) . subscribe ( ( ) => {
171
+ this . backdropClick . emit ( null ) ;
172
+ } ) ;
173
+ }
174
+ }
175
+
176
+ /** Detaches the overlay and unsubscribes to backdrop clicks if backdrop exists */
177
+ private _detachOverlay ( ) {
178
+ if ( this . _overlayRef ) {
179
+ this . _overlayRef . detach ( ) ;
180
+ }
181
+
182
+ if ( this . _backdropSubscription ) {
183
+ this . _backdropSubscription . unsubscribe ( ) ;
184
+ this . _backdropSubscription = null ;
185
+ }
100
186
}
101
187
102
188
/** Destroys the overlay created by this directive. */
103
189
private _destroyOverlay ( ) {
104
- this . _overlayRef . dispose ( ) ;
190
+ if ( this . _overlayRef ) {
191
+ this . _overlayRef . dispose ( ) ;
192
+ }
193
+
194
+ if ( this . _backdropSubscription ) {
195
+ this . _backdropSubscription . unsubscribe ( ) ;
196
+ }
105
197
}
106
198
}
107
199
0 commit comments