@@ -13,6 +13,8 @@ import {
1313 TemplateRef ,
1414 ComponentRef ,
1515 ElementRef ,
16+ Directive ,
17+ AfterViewInit ,
1618} from '@angular/core' ;
1719import { CommonModule } from '@angular/common' ;
1820import { CdkPortal , CdkPortalOutlet , PortalModule } from './portal-directives' ;
@@ -367,7 +369,7 @@ describe('Portals', () => {
367369 let componentFactoryResolver : ComponentFactoryResolver ;
368370 let someViewContainerRef : ViewContainerRef ;
369371 let someInjector : Injector ;
370- let someFixture : ComponentFixture < any > ;
372+ let someFixture : ComponentFixture < ArbitraryViewContainerRefComponent > ;
371373 let someDomElement : HTMLElement ;
372374 let host : DomPortalOutlet ;
373375 let injector : Injector ;
@@ -403,6 +405,19 @@ describe('Portals', () => {
403405 expect ( someDomElement . innerHTML ) . toBe ( '' ) ;
404406 } ) ;
405407
408+ it ( 'should move the DOM nodes before running change detection' , ( ) => {
409+ someFixture . detectChanges ( ) ;
410+ let portal = new TemplatePortal ( someFixture . componentInstance . template , someViewContainerRef ) ;
411+
412+ host . attachTemplatePortal ( portal ) ;
413+ someFixture . detectChanges ( ) ;
414+
415+ expect ( someFixture . componentInstance . saveParentNodeOnInit . parentOnViewInit )
416+ . toBe ( someDomElement ) ;
417+
418+ host . dispose ( ) ;
419+ } ) ;
420+
406421 it ( 'should attach and detach a component portal with a given injector' , ( ) => {
407422 let fixture = TestBed . createComponent ( ArbitraryViewContainerRefComponent ) ;
408423 someViewContainerRef = fixture . componentInstance . viewContainerRef ;
@@ -575,12 +590,38 @@ class PizzaMsg {
575590 constructor ( @Optional ( ) public snack : Chocolate ) { }
576591}
577592
593+ /**
594+ * Saves the parent node that the directive was attached to on init.
595+ * Useful to see where the element was in the DOM when it was first attached.
596+ */
597+ @Directive ( {
598+ selector : '[savesParentNodeOnInit]'
599+ } )
600+ class SaveParentNodeOnInit implements AfterViewInit {
601+ parentOnViewInit : HTMLElement ;
602+
603+ constructor ( private _elementRef : ElementRef < HTMLElement > ) { }
604+
605+ ngAfterViewInit ( ) {
606+ this . parentOnViewInit = this . _elementRef . nativeElement . parentElement ! ;
607+ }
608+ }
609+
578610/** Simple component to grab an arbitrary ViewContainerRef */
579611@Component ( {
580612 selector : 'some-placeholder' ,
581- template : '<p>Hello</p>'
613+ template : `
614+ <p>Hello</p>
615+
616+ <ng-template #template>
617+ <div savesParentNodeOnInit></div>
618+ </ng-template>
619+ `
582620} )
583621class ArbitraryViewContainerRefComponent {
622+ @ViewChild ( 'template' , { static : false } ) template : TemplateRef < any > ;
623+ @ViewChild ( SaveParentNodeOnInit , { static : false } ) saveParentNodeOnInit : SaveParentNodeOnInit ;
624+
584625 constructor ( public viewContainerRef : ViewContainerRef , public injector : Injector ) { }
585626}
586627
@@ -666,7 +707,7 @@ const TEST_COMPONENTS = [
666707@NgModule ( {
667708 imports : [ CommonModule , PortalModule ] ,
668709 exports : TEST_COMPONENTS ,
669- declarations : TEST_COMPONENTS ,
710+ declarations : [ ... TEST_COMPONENTS , SaveParentNodeOnInit ] ,
670711 entryComponents : TEST_COMPONENTS ,
671712} )
672713class PortalTestModule { }
0 commit comments