Skip to content

Commit ba324cd

Browse files
author
vakrilov
committed
DetachedLoader ChangeDetection fix
1 parent 680a296 commit ba324cd

File tree

1 file changed

+27
-4
lines changed

1 file changed

+27
-4
lines changed

nativescript-angular/common/detached-loader.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
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

34
type AnyComponentRef = ComponentRef<any>;
45
interface 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

Comments
 (0)