@@ -14,6 +14,8 @@ import {
14
14
ViewChild ,
15
15
ViewChildren ,
16
16
ViewContainerRef ,
17
+ Directive ,
18
+ AfterViewInit ,
17
19
} from '@angular/core' ;
18
20
import { ComponentFixture , inject , TestBed } from '@angular/core/testing' ;
19
21
import { DomPortalOutlet } from './dom-portal-outlet' ;
@@ -404,7 +406,7 @@ describe('Portals', () => {
404
406
let componentFactoryResolver : ComponentFactoryResolver ;
405
407
let someViewContainerRef : ViewContainerRef ;
406
408
let someInjector : Injector ;
407
- let someFixture : ComponentFixture < any > ;
409
+ let someFixture : ComponentFixture < ArbitraryViewContainerRefComponent > ;
408
410
let someDomElement : HTMLElement ;
409
411
let host : DomPortalOutlet ;
410
412
let injector : Injector ;
@@ -440,6 +442,19 @@ describe('Portals', () => {
440
442
expect ( someDomElement . innerHTML ) . toBe ( '' ) ;
441
443
} ) ;
442
444
445
+ it ( 'should move the DOM nodes before running change detection' , ( ) => {
446
+ someFixture . detectChanges ( ) ;
447
+ let portal = new TemplatePortal ( someFixture . componentInstance . template , someViewContainerRef ) ;
448
+
449
+ host . attachTemplatePortal ( portal ) ;
450
+ someFixture . detectChanges ( ) ;
451
+
452
+ expect ( someFixture . componentInstance . saveParentNodeOnInit . parentOnViewInit )
453
+ . toBe ( someDomElement ) ;
454
+
455
+ host . dispose ( ) ;
456
+ } ) ;
457
+
443
458
it ( 'should attach and detach a component portal with a given injector' , ( ) => {
444
459
let fixture = TestBed . createComponent ( ArbitraryViewContainerRefComponent ) ;
445
460
someViewContainerRef = fixture . componentInstance . viewContainerRef ;
@@ -634,12 +649,38 @@ class PizzaMsg {
634
649
constructor ( @Optional ( ) public snack : Chocolate ) { }
635
650
}
636
651
652
+ /**
653
+ * Saves the parent node that the directive was attached to on init.
654
+ * Useful to see where the element was in the DOM when it was first attached.
655
+ */
656
+ @Directive ( {
657
+ selector : '[savesParentNodeOnInit]'
658
+ } )
659
+ class SaveParentNodeOnInit implements AfterViewInit {
660
+ parentOnViewInit : HTMLElement ;
661
+
662
+ constructor ( private _elementRef : ElementRef < HTMLElement > ) { }
663
+
664
+ ngAfterViewInit ( ) {
665
+ this . parentOnViewInit = this . _elementRef . nativeElement . parentElement ! ;
666
+ }
667
+ }
668
+
637
669
/** Simple component to grab an arbitrary ViewContainerRef */
638
670
@Component ( {
639
671
selector : 'some-placeholder' ,
640
- template : '<p>Hello</p>'
672
+ template : `
673
+ <p>Hello</p>
674
+
675
+ <ng-template #template>
676
+ <div savesParentNodeOnInit></div>
677
+ </ng-template>
678
+ `
641
679
} )
642
680
class ArbitraryViewContainerRefComponent {
681
+ @ViewChild ( 'template' , { static : false } ) template : TemplateRef < any > ;
682
+ @ViewChild ( SaveParentNodeOnInit , { static : false } ) saveParentNodeOnInit : SaveParentNodeOnInit ;
683
+
643
684
constructor ( public viewContainerRef : ViewContainerRef , public injector : Injector ) { }
644
685
}
645
686
@@ -731,7 +772,7 @@ const TEST_COMPONENTS = [
731
772
@NgModule ( {
732
773
imports : [ CommonModule , PortalModule ] ,
733
774
exports : TEST_COMPONENTS ,
734
- declarations : TEST_COMPONENTS ,
775
+ declarations : [ ... TEST_COMPONENTS , SaveParentNodeOnInit ] ,
735
776
entryComponents : TEST_COMPONENTS ,
736
777
} )
737
778
class PortalTestModule { }
0 commit comments