@@ -12,7 +12,10 @@ import {
1212 transition ,
1313 AnimationTransitionEvent ,
1414 ElementRef ,
15- Optional
15+ Optional ,
16+ ChangeDetectorRef ,
17+ AfterViewChecked ,
18+ AfterContentChecked ,
1619} from '@angular/core' ;
1720import { TemplatePortal , PortalHostDirective , Dir , LayoutDirection } from '../core' ;
1821import 'rxjs/add/operator/map' ;
@@ -65,7 +68,7 @@ export type MdTabBodyOriginState = 'left' | 'right';
6568 ] )
6669 ]
6770} )
68- export class MdTabBody implements OnInit {
71+ export class MdTabBody implements OnInit , AfterViewChecked , AfterContentChecked {
6972 /** The portal host inside of this container into which the tab body content will be loaded. */
7073 @ViewChild ( PortalHostDirective ) _portalHost : PortalHostDirective ;
7174
@@ -92,6 +95,10 @@ export class MdTabBody implements OnInit {
9295 }
9396 }
9497
98+ /** Whether the element is allowed to be animated. */
99+ _canBeAnimated : boolean = false ;
100+
101+ /** The origin position from which this tab should appear when it is centered into view. */
95102 _origin : MdTabBodyOriginState ;
96103
97104 /** The origin position from which this tab should appear when it is centered into view. */
@@ -106,7 +113,10 @@ export class MdTabBody implements OnInit {
106113 }
107114 }
108115
109- constructor ( private _elementRef : ElementRef , @Optional ( ) private _dir : Dir ) { }
116+ constructor (
117+ @Optional ( ) private _dir : Dir ,
118+ private _elementRef : ElementRef ,
119+ private _changeDetectorRef : ChangeDetectorRef ) { }
110120
111121 /**
112122 * After initialized, check if the content is centered and has an origin. If so, set the
@@ -128,6 +138,25 @@ export class MdTabBody implements OnInit {
128138 }
129139 }
130140
141+ /**
142+ * After the content has been checked, determines whether the element should be allowed to
143+ * animate. This has to be limited, because under a specific set of circumstances (see #2151),
144+ * the animations can be triggered too early, which either crashes Chrome by putting it into an
145+ * infinite loop (with Angular < 2.3.0) or throws an error because the element doesn't have a
146+ * computed style (with Angular > 2.3.0). This can alternatively be determined by checking the
147+ * transform: canBeAnimated = getComputedStyle(element) !== '', however document.contains should
148+ * be faster since it doesn't cause a reflow.
149+ */
150+ ngAfterContentChecked ( ) {
151+ if ( ! this . _canBeAnimated ) {
152+ this . _canBeAnimated = document . contains ( this . _elementRef . nativeElement ) ;
153+
154+ if ( this . _canBeAnimated ) {
155+ this . _changeDetectorRef . markForCheck ( ) ;
156+ }
157+ }
158+ }
159+
131160 _onTranslateTabStarted ( e : AnimationTransitionEvent ) {
132161 if ( this . _isCenterPosition ( e . toState ) ) {
133162 this . onCentering . emit ( this . _elementRef . nativeElement . clientHeight ) ;
@@ -151,7 +180,6 @@ export class MdTabBody implements OnInit {
151180 return this . _dir && this . _dir . value === 'rtl' ? 'rtl' : 'ltr' ;
152181 }
153182
154-
155183 /** Whether the provided position state is considered center, regardless of origin. */
156184 private _isCenterPosition ( position : MdTabBodyPositionState | string ) : boolean {
157185 return position == 'center' ||
0 commit comments