1- import { ComponentRef , ViewContainerRef , Component , Type , ViewChild , ComponentResolver } from '@angular/core' ;
1+ import { ComponentRef , ViewContainerRef , Component , Type , ViewChild , ComponentResolver , ChangeDetectorRef , Host } from '@angular/core' ;
2+ import trace = require( "trace" ) ;
23
34type AnyComponentRef = ComponentRef < any > ;
45interface PendingLoadEntry {
56 componentType : Type ;
67 resolveCallback : ( AnyComponentRef ) => void ;
78}
89
10+ export const CATEGORY = "detached-loader" ;
11+ function log ( message : string ) {
12+ trace . write ( message , CATEGORY ) ;
13+ }
14+ 15+ 916/**
1017 * Wrapper component used for loading components when navigating
1118 * It uses DetachedContainer as selector so that it is containerRef is not attached to the visual tree.
@@ -20,10 +27,11 @@ export class DetachedLoader {
2027 private viewLoaded = false ;
2128 private pendingLoads : PendingLoadEntry [ ] = [ ] ;
2229
23- constructor ( private compiler : ComponentResolver ) {
24- }
30+ constructor ( private compiler : ComponentResolver , private changeDetector : ChangeDetectorRef ) { }
2531
2632 public ngAfterViewInit ( ) {
33+ log ( "DetachedLoader.ngAfterViewInit" ) ;
34+ 2735 this . viewLoaded = true ;
2836 this . pendingLoads . forEach ( loadEntry => {
2937 this . loadInLocation ( loadEntry . componentType ) . then ( loadedRef => {
@@ -35,15 +43,30 @@ export class DetachedLoader {
3543 private loadInLocation ( componentType : Type ) : Promise < ComponentRef < any > > {
3644 return this . compiler . resolveComponent ( componentType ) . then ( ( componentFactory ) => {
3745 return this . containerRef . createComponent ( componentFactory , this . containerRef . length , this . containerRef . parentInjector , null ) ;
38- } ) ;
46+ } ) . then ( ( compRef ) => {
47+ log ( "DetachedLoader.loadInLocation component loaded -> markForCheck" ) ;
48+ // Component is created, buit may not be checked if we are loading
49+ // inside component with OnPush CD strategy. Mark us for check to be sure CD will reach us.
50+ // We are inside a promise here so no need for setTimeout - CD should trigger after the promise.
51+ this . changeDetector . markForCheck ( ) ;
52+ return compRef ;
53+ } )
3954 }
4055
4156 public loadComponent ( componentType : Type ) : Promise < ComponentRef < any > > {
57+ log ( "DetachedLoader.loadComponent viewLoaded: " + this . viewLoaded ) ;
58+ 4259 // Check if called before placeholder is initialized.
4360 // Delay load if so.
4461 if ( this . viewLoaded ) {
4562 return this . loadInLocation ( componentType ) ;
4663 } else {
64+ // loadComponent called, but detached-loader is still not initialized.
65+ // Mark it for change and trigger change detection to be sure it will be initialized,
66+ // so that loading can conitionue.
67+ log ( "DetachedLoader.loadComponent -> markForCheck(with setTimeout())" )
68+ setTimeout ( ( ) => this . changeDetector . markForCheck ( ) , 0 ) ;
69+ 4770 return new Promise ( ( resolve , reject ) => {
4871 this . pendingLoads . push ( {
4972 componentType : componentType ,
0 commit comments