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