@@ -12,6 +12,9 @@ import {
12
12
ApplicationRef ,
13
13
TemplateRef ,
14
14
ComponentRef ,
15
+ Directive ,
16
+ AfterViewInit ,
17
+ ElementRef ,
15
18
} from '@angular/core' ;
16
19
import { CommonModule } from '@angular/common' ;
17
20
import { CdkPortal , CdkPortalOutlet , PortalModule } from './portal-directives' ;
@@ -336,8 +339,8 @@ describe('Portals', () => {
336
339
let componentFactoryResolver : ComponentFactoryResolver ;
337
340
let someViewContainerRef : ViewContainerRef ;
338
341
let someInjector : Injector ;
339
- let someFixture : ComponentFixture < any > ;
340
- let someDomElement : HTMLElement ;
342
+ let someFixture : ComponentFixture < ArbitraryViewContainerRefComponent > ;
343
+ let outletNode : HTMLElement ;
341
344
let host : DomPortalOutlet ;
342
345
let injector : Injector ;
343
346
let appRef : ApplicationRef ;
@@ -350,8 +353,8 @@ describe('Portals', () => {
350
353
} ) ) ;
351
354
352
355
beforeEach ( ( ) => {
353
- someDomElement = document . createElement ( 'div' ) ;
354
- host = new DomPortalOutlet ( someDomElement , componentFactoryResolver , appRef , injector ) ;
356
+ outletNode = document . createElement ( 'div' ) ;
357
+ host = new DomPortalOutlet ( outletNode , componentFactoryResolver , appRef , injector ) ;
355
358
356
359
someFixture = TestBed . createComponent ( ArbitraryViewContainerRefComponent ) ;
357
360
someViewContainerRef = someFixture . componentInstance . viewContainerRef ;
@@ -364,11 +367,23 @@ describe('Portals', () => {
364
367
let componentInstance : PizzaMsg = portal . attach ( host ) . instance ;
365
368
366
369
expect ( componentInstance instanceof PizzaMsg ) . toBe ( true ) ;
367
- expect ( someDomElement . textContent ) . toContain ( 'Pizza' ) ;
370
+ expect ( outletNode . textContent ) . toContain ( 'Pizza' ) ;
368
371
369
372
host . detach ( ) ;
370
373
371
- expect ( someDomElement . innerHTML ) . toBe ( '' ) ;
374
+ expect ( outletNode . innerHTML ) . toBe ( '' ) ;
375
+ } ) ;
376
+
377
+ it ( 'should move the DOM nodes before running change detection' , ( ) => {
378
+ someFixture . detectChanges ( ) ;
379
+ let portal = new TemplatePortal ( someFixture . componentInstance . template , someViewContainerRef ) ;
380
+
381
+ host . attachTemplatePortal ( portal ) ;
382
+ someFixture . detectChanges ( ) ;
383
+
384
+ expect ( someFixture . componentInstance . saveParentNodeOnInit . parentOnViewInit ) . toBe ( outletNode ) ;
385
+
386
+ host . dispose ( ) ;
372
387
} ) ;
373
388
374
389
it ( 'should attach and detach a component portal with a given injector' , ( ) => {
@@ -383,12 +398,12 @@ describe('Portals', () => {
383
398
fixture . detectChanges ( ) ;
384
399
385
400
expect ( componentInstance instanceof PizzaMsg ) . toBe ( true ) ;
386
- expect ( someDomElement . textContent ) . toContain ( 'Pizza' ) ;
387
- expect ( someDomElement . textContent ) . toContain ( 'Chocolate' ) ;
401
+ expect ( outletNode . textContent ) . toContain ( 'Pizza' ) ;
402
+ expect ( outletNode . textContent ) . toContain ( 'Chocolate' ) ;
388
403
389
404
host . detach ( ) ;
390
405
391
- expect ( someDomElement . innerHTML ) . toBe ( '' ) ;
406
+ expect ( outletNode . innerHTML ) . toBe ( '' ) ;
392
407
} ) ;
393
408
394
409
it ( 'should attach and detach a template portal' , ( ) => {
@@ -397,7 +412,7 @@ describe('Portals', () => {
397
412
398
413
fixture . componentInstance . cakePortal . attach ( host ) ;
399
414
400
- expect ( someDomElement . textContent ) . toContain ( 'Cake' ) ;
415
+ expect ( outletNode . textContent ) . toContain ( 'Cake' ) ;
401
416
} ) ;
402
417
403
418
it ( 'should render a template portal with an inner template' , ( ) => {
@@ -406,7 +421,7 @@ describe('Portals', () => {
406
421
407
422
fixture . componentInstance . portalWithTemplate . attach ( host ) ;
408
423
409
- expect ( someDomElement . textContent ) . toContain ( 'Durian' ) ;
424
+ expect ( outletNode . textContent ) . toContain ( 'Durian' ) ;
410
425
} ) ;
411
426
412
427
it ( 'should attach and detach a template portal with a binding' , ( ) => {
@@ -426,17 +441,17 @@ describe('Portals', () => {
426
441
fixture . detectChanges ( ) ;
427
442
428
443
// Expect that the content of the attached portal is present.
429
- expect ( someDomElement . textContent ) . toContain ( 'Banana - fresh' ) ;
444
+ expect ( outletNode . textContent ) . toContain ( 'Banana - fresh' ) ;
430
445
431
446
// When updating the binding value.
432
447
testAppComponent . fruit = 'Mango' ;
433
448
fixture . detectChanges ( ) ;
434
449
435
450
// Expect the new value to be reflected in the rendered output.
436
- expect ( someDomElement . textContent ) . toContain ( 'Mango' ) ;
451
+ expect ( outletNode . textContent ) . toContain ( 'Mango' ) ;
437
452
438
453
host . detach ( ) ;
439
- expect ( someDomElement . innerHTML ) . toBe ( '' ) ;
454
+ expect ( outletNode . innerHTML ) . toBe ( '' ) ;
440
455
} ) ;
441
456
442
457
it ( 'should change the attached portal' , ( ) => {
@@ -448,12 +463,12 @@ describe('Portals', () => {
448
463
449
464
appFixture . componentInstance . piePortal . attach ( host ) ;
450
465
451
- expect ( someDomElement . textContent ) . toContain ( 'Pie' ) ;
466
+ expect ( outletNode . textContent ) . toContain ( 'Pie' ) ;
452
467
453
468
host . detach ( ) ;
454
469
host . attach ( new ComponentPortal ( PizzaMsg , someViewContainerRef ) ) ;
455
470
456
- expect ( someDomElement . textContent ) . toContain ( 'Pizza' ) ;
471
+ expect ( outletNode . textContent ) . toContain ( 'Pizza' ) ;
457
472
} ) ;
458
473
459
474
it ( 'should attach and detach a component portal without a ViewContainerRef' , ( ) => {
@@ -463,17 +478,17 @@ describe('Portals', () => {
463
478
464
479
expect ( componentInstance instanceof PizzaMsg )
465
480
. toBe ( true , 'Expected a PizzaMsg component to be created' ) ;
466
- expect ( someDomElement . textContent )
481
+ expect ( outletNode . textContent )
467
482
. toContain ( 'Pizza' , 'Expected the static string "Pizza" in the DomPortalOutlet.' ) ;
468
483
469
484
componentInstance . snack = new Chocolate ( ) ;
470
485
someFixture . detectChanges ( ) ;
471
- expect ( someDomElement . textContent )
486
+ expect ( outletNode . textContent )
472
487
. toContain ( 'Chocolate' , 'Expected the bound string "Chocolate" in the DomPortalOutlet' ) ;
473
488
474
489
host . detach ( ) ;
475
490
476
- expect ( someDomElement . innerHTML )
491
+ expect ( outletNode . innerHTML )
477
492
. toBe ( '' , 'Expected the DomPortalOutlet to be empty after detach' ) ;
478
493
} ) ;
479
494
@@ -529,12 +544,38 @@ class PizzaMsg {
529
544
constructor ( @Optional ( ) public snack : Chocolate ) { }
530
545
}
531
546
547
+ /**
548
+ * Saves the parent node that the directive was attached to on init.
549
+ * Useful to see where the element was in the DOM when it was first attached.
550
+ */
551
+ @Directive ( {
552
+ selector : '[savesParentNodeOnInit]'
553
+ } )
554
+ class SaveParentNodeOnInit implements AfterViewInit {
555
+ parentOnViewInit : HTMLElement ;
556
+
557
+ constructor ( private _elementRef : ElementRef < HTMLElement > ) { }
558
+
559
+ ngAfterViewInit ( ) {
560
+ this . parentOnViewInit = this . _elementRef . nativeElement . parentElement ! ;
561
+ }
562
+ }
563
+
532
564
/** Simple component to grab an arbitrary ViewContainerRef */
533
565
@Component ( {
534
566
selector : 'some-placeholder' ,
535
- template : '<p>Hello</p>'
567
+ template : `
568
+ <p>Hello</p>
569
+
570
+ <ng-template #template>
571
+ <div savesParentNodeOnInit></div>
572
+ </ng-template>
573
+ `
536
574
} )
537
575
class ArbitraryViewContainerRefComponent {
576
+ @ViewChild ( 'template' , { static : false } ) template : TemplateRef < any > ;
577
+ @ViewChild ( SaveParentNodeOnInit , { static : false } ) saveParentNodeOnInit : SaveParentNodeOnInit ;
578
+
538
579
constructor ( public viewContainerRef : ViewContainerRef , public injector : Injector ) { }
539
580
}
540
581
@@ -615,7 +656,7 @@ const TEST_COMPONENTS = [
615
656
@NgModule ( {
616
657
imports : [ CommonModule , PortalModule ] ,
617
658
exports : TEST_COMPONENTS ,
618
- declarations : TEST_COMPONENTS ,
659
+ declarations : [ ... TEST_COMPONENTS , SaveParentNodeOnInit ] ,
619
660
entryComponents : TEST_COMPONENTS ,
620
661
} )
621
662
class PortalTestModule { }
0 commit comments