@@ -14,10 +14,12 @@ import {
14
14
EventEmitter ,
15
15
OnInit ,
16
16
ElementRef ,
17
+ Directive ,
17
18
Optional ,
18
- AfterViewChecked ,
19
19
ViewEncapsulation ,
20
20
ChangeDetectionStrategy ,
21
+ ComponentFactoryResolver ,
22
+ ViewContainerRef ,
21
23
} from '@angular/core' ;
22
24
import {
23
25
trigger ,
@@ -29,7 +31,7 @@ import {
29
31
} from '@angular/animations' ;
30
32
import { TemplatePortal , PortalHostDirective } from '@angular/cdk/portal' ;
31
33
import { Directionality , Direction } from '@angular/cdk/bidi' ;
32
-
34
+ import { Subscription } from 'rxjs/Subscription' ;
33
35
34
36
/**
35
37
* These position states are used internally as animation states for the tab body. Setting the
@@ -52,6 +54,52 @@ export type MdTabBodyPositionState =
52
54
*/
53
55
export type MdTabBodyOriginState = 'left' | 'right' ;
54
56
57
+ /**
58
+ * The portal host directive for the contents of the tab.
59
+ * @docs -private
60
+ */
61
+ @Directive ( {
62
+ selector : '[matTabBodyHost]'
63
+ } )
64
+ export class TabsBodyPortal extends PortalHostDirective implements OnInit {
65
+ /** Whether the tab body should be visible. */
66
+ visible = false ;
67
+ /** A subscription to events for when the tab body begins centering. */
68
+ centeringSub : Subscription ;
69
+ /** A subscription to events for when the tab body completes leaving from center. */
70
+ leavingCenterSub : Subscription ;
71
+
72
+ constructor (
73
+ _componentFactoryResolver : ComponentFactoryResolver ,
74
+ _viewContainerRef : ViewContainerRef ,
75
+ private host : MdTabBody ) {
76
+ super ( _componentFactoryResolver , _viewContainerRef ) ;
77
+ }
78
+
79
+ /** Set up subscriptions for changing visibility and set initial visibility. */
80
+ ngOnInit ( ) : void {
81
+ this . centeringSub = this . host . onCentering . subscribe ( ( ) => this . setVisibility ( true ) ) ;
82
+ this . leavingCenterSub = this . host . afterLeavingCenter . subscribe ( ( ) => this . setVisibility ( false ) ) ;
83
+ if ( this . host . _isCenterPosition ( this . host . _position ) ) {
84
+ this . setVisibility ( true ) ;
85
+ }
86
+ }
87
+
88
+ /** Clean up subscriptions. */
89
+ ngOnDestroy ( ) : void {
90
+ this . leavingCenterSub . unsubscribe ( ) ;
91
+ this . centeringSub . unsubscribe ( ) ;
92
+ }
93
+
94
+ /** Set the visiblity of the tab body content, attaching the content if necessary. */
95
+ setVisibility ( visible : boolean ) : void {
96
+ if ( visible && ! this . hasAttached ( ) ) {
97
+ this . attach ( this . host . _content ) ;
98
+ }
99
+ this . visible = visible ;
100
+ }
101
+ }
102
+
55
103
/**
56
104
* Wrapper for the contents of a tab.
57
105
* @docs -private
@@ -88,13 +136,16 @@ export type MdTabBodyOriginState = 'left' | 'right';
88
136
] )
89
137
]
90
138
} )
91
- export class MdTabBody implements OnInit , AfterViewChecked {
139
+ export class MdTabBody implements OnInit {
92
140
/** The portal host inside of this container into which the tab body content will be loaded. */
93
- @ViewChild ( PortalHostDirective ) _portalHost : PortalHostDirective ;
141
+ @ViewChild ( TabsBodyPortal ) _portalHost : TabsBodyPortal ;
94
142
95
143
/** Event emitted when the tab begins to animate towards the center as the active tab. */
96
144
@Output ( ) onCentering : EventEmitter < number > = new EventEmitter < number > ( ) ;
97
145
146
+ /** Event emitted when the tab completes its animation away from the center. */
147
+ @Output ( ) afterLeavingCenter : EventEmitter < number > = new EventEmitter < number > ( ) ;
148
+
98
149
/** Event emitted when the tab completes its animation towards the center. */
99
150
@Output ( ) onCentered : EventEmitter < void > = new EventEmitter < void > ( true ) ;
100
151
@@ -141,26 +192,16 @@ export class MdTabBody implements OnInit, AfterViewChecked {
141
192
}
142
193
}
143
194
144
- /**
145
- * After the view has been set, check if the tab content is set to the center and attach the
146
- * content if it is not already attached.
147
- */
148
- ngAfterViewChecked ( ) {
149
- if ( this . _isCenterPosition ( this . _position ) && ! this . _portalHost . hasAttached ( ) ) {
150
- this . _portalHost . attach ( this . _content ) ;
151
- }
152
- }
153
-
154
- _onTranslateTabStarted ( e : AnimationEvent ) {
195
+ _onTranslateTabStarted ( e : AnimationEvent ) : void {
155
196
if ( this . _isCenterPosition ( e . toState ) ) {
156
197
this . onCentering . emit ( this . _elementRef . nativeElement . clientHeight ) ;
157
198
}
158
199
}
159
200
160
- _onTranslateTabComplete ( e : AnimationEvent ) {
161
- // If the end state is that the tab is not centered, then detach the content .
201
+ _onTranslateTabComplete ( e : AnimationEvent ) : void {
202
+ // If the end state is that the tab is not centered, emit an event .
162
203
if ( ! this . _isCenterPosition ( e . toState ) && ! this . _isCenterPosition ( this . _position ) ) {
163
- this . _portalHost . detach ( ) ;
204
+ this . afterLeavingCenter . emit ( ) ;
164
205
}
165
206
166
207
// If the transition to the center is complete, emit an event.
@@ -175,7 +216,7 @@ export class MdTabBody implements OnInit, AfterViewChecked {
175
216
}
176
217
177
218
/** Whether the provided position state is considered center, regardless of origin. */
178
- private _isCenterPosition ( position : MdTabBodyPositionState | string ) : boolean {
219
+ _isCenterPosition ( position : MdTabBodyPositionState | string ) : boolean {
179
220
return position == 'center' ||
180
221
position == 'left-origin-center' ||
181
222
position == 'right-origin-center' ;
0 commit comments