nativescript-angular: TypeError: Cannot read property 'destroyed' of null
<ListView class="list-group" [items]="albums" >
<ng-template let-album="item">
<StackLayout (loaded)="loadComplete()" class="list-group-item">
<Label [text]="album.name" class=" list-group-item-heading"></Label>
<Label class="list-group-item-text" text="{{album.images.length}} Images"></Label>
<WrapLayout *ngIf="album.images.length>0" width="100%" class="list-group" >
<WebImage stretch="aspectFit" backgroundColor="gray"
[src]="image.thumbnailUrl" *ngFor="let image of album.images"
width="20%" [height]="imageElement.getActualSize().width" #imageElement></WebImage>
</WrapLayout >
</StackLayout>
</ng-template>
</ListView>
if we use above code then app is starting without any errors and output is as expected.
but using below code i get the error that "ERROR TypeError: Cannot read property ‘images’ of null "
<ScrollView class="list-group" >
<StackLayout>
<StackLayout *ngFor="let album of albums" (loaded)="loadComplete()" class="list-group-item">
<Label [text]="album.name" class=" list-group-item-heading"></Label>
<Label class="list-group-item-text" text="{{album.images.length}} Images"></Label>
<WrapLayout *ngIf="album.images.length>0" width="100%" class="list-group" >
<WebImage stretch="aspectFit" backgroundColor="gray"
[src]="image.thumbnailUrl" *ngFor="let image of album.images"
width="20%" [height]="imageElement.getActualSize().width" #imageElement></WebImage>
</WrapLayout >
</StackLayout>
</StackLayout>
</ScrollView>
we can clearly state that both code are equivalent and should give similar output. but last gives error “ERROR TypeError: Cannot read property ‘images’ of null”
Detailed error is like this:
JS: ERROR CONTEXT [object Object]
JS: ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'destroy
ed' of null
JS: TypeError: Cannot read property 'destroyed' of null
JS: at ViewContainerRef_.move (file:///data/data/org.nativescript.bunkerzon/
files/app/tns_modules/@angular/core/bundles/core.umd.js:11506:20)
JS: at file:///data/data/org.nativescript.bunkerzon/files/app/tns_modules/@a
ngular/common/bundles/common.umd.js:2652:38
JS: at DefaultIterableDiffer.forEachOperation (file:///data/data/org.natives
cript.bunkerzon/files/app/tns_modules/@angular/core/bundles/core.umd.js:7451:17)
JS: at NgForOf._applyChanges (file:///data/data/org.nativescript.bunkerzon/f
iles/app/tns_modules/@angular/common/bundles/common.umd.js:2641:17)
JS: at NgForOf.ngDoCheck (file:///data/data/org.nativescript.bunkerzon/files
/app/tns_modules/@angular/common/bundles/common.umd.js:2627:22)
JS: at checkAndUpdateDirectiveInline (file:///data/data/org.nativescript.bun
kerzon/files/app/tns_modules/@angular/core/bundles/core.umd.js:12410:19)
JS: at checkAndUpdateNodeInline (file:///data/data/org.nativescript.bunkerzo
n/files/app/tns_modules/@angular/core/bundles/core.umd.js:13931:20)
JS: at checkAndUpdateNode (file:///data/data/org.nativescript.bunkerzon/file
s/app/tns_modules/@angular/core/bundles/core.umd.js:13874:16)
JS: at debugCheckAndUpdateNode (file:///data/data/org.nativescript.bunkerzon
/files/app/tns_modules/@angular/core/bundles/core.umd.js:14767:76)
JS: at debugCheckDirectivesFn (file:///data/data/org.nativescript.bunkerzon/
files/app/tns_modules/@angular/core/bundles/core.umd.js:14708:13)
JS: at Object.eval [as updateDirectives] (ng:///HomeModule/HomeComponent.ngf
actory.js:89:9)
JS: at Object.debugUpdateDirectives [as updateDirectives] (file:///data/data
/org.nativescript.bunkerzon/files/app/tns_modules/@angular/core/bundles/core.umd
.js:14693:21)
JS: at checkAndUpdateView (file:///data/data/org.nativescript.bunkerzon/file
s/app/tns_modules/@angular/core/bundles/core.umd.js:13840:14)
JS: at callViewAction (file:///data/data/org.nativescript.bunkerzon/files/ap
p/tns_modules/@angular/core/bundles/core.umd.js:14191:21)
JS: at execEmbeddedViewsAction (file:///data/data/org.nativescript.bunkerzon
/files/app/tns_modules/@angular/core/bundles/core.umd.js:14149:17)
JS: synct contact success [object Object]
JS: ERROR TypeError: Cannot read property 'images' of null
JS: ERROR CONTEXT [object Object]
i had also tried binding label text to function in which local album variable gets printed like below
<Label [text]="conDir(group)" class=" list-group-item-heading"></Label>
conDir(a){ console.log(a.id) console.log(a.name) return a.name; }
Looking at logs i can verify that “album” is not null and has correct value as it should have. so i have no idea what can be wrong.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 19 (9 by maintainers)
@NathanaelA While writing the PR and tests, the problem seems to be with
nativescript-zone.If you trigger
fixture.detectChanges()orfixture.autoDetectChanges(true), the problem does not happen, but if you triggerfixture.autoDetectChanges(true)and add asetTimeoutyou’ll get the following error:Angular has an “NgZone” which contains an inner zone (actual angular zone) and outer zone (code running without angular “knowning”). The code from
onItemLoadingis called on the<root>zone (since it’s being bound byonand not by(event)=...). The zones in NS core seem to be doing:which means if a request came from the angular zone,
Zone.current.nameisangular, so it’ll trigger CD when it’s finished.Now for some reason, this bug only happens when you have other tasks queued up (which is often the case in real apps), so it can’t be reproduced in unit testing, which probably means the issue is not with running the code inside the angular zone, but something with zone itself. My solution of running it inside the ngzone is actually more of a workaround.
On all cases,
onItemLoadingwas called in zone<root>.After over 1 year of thinking about this on and off I FINALLY found the solution, and the problem is way deeper than I originally thought.
The problem is specifically with
onItemLoading.onItemLoadingcallsview.detectChanges()inside a Zone, but NOT THE ANGULAR ZONEview.detectChanges()is running in a zone, but not in the angular zoneThis happens for 2 reasons:
loadedand others will always trigger when they happened, even if there are other tasks running. This is different from the web event loop, where the event callbacks are queuedunloadedbecause the element will have been destroyed by then, as it happens DURING the destroy. This resulted in my(unloaded)never firing as it waited for the whole destruction process to fire, and by then the subscription had been closed.This discovery raises some issues:
requestAnimationFramehas not been patched inzone-nativescripthttps://github.com/NativeScript/nativescript-angular/blob/master/nativescript-angular/zone-js/dist/zone-nativescript.js#L1676nativescript-angularwheredetectChangesormarkForCheckare being called outside the ngzone. That I could find: dialogs, DetachedLoader, and templated-items-comp.I’ll write a PR wrapping all
detectChangesin the ngzone for the time being, but the other points must be considered.Ok, I found why this error occurs. Wrapping the callback in NgZone.run breaks the code.
See: https://play.nativescript.org/?template=play-ng&id=hpl6OJ&v=6
this is the same logic being used in nativescript-angular renderer https://github.com/NativeScript/nativescript-angular/blob/309ed7b0de824a869b1b1c07b4a25928f7a754e1/nativescript-angular/renderer.ts#L296
It seems ngzone tries to check if the element is destroyed, but at the time of loading and unloading, it’s null, so it throws the error.
Edit:
More testing. Using a setTimeout 0 to make it run on the next angular cycle also fixes the problem:
AND the item is available on load.
Forcing a change detection with
this.cdref.detectChanges();crashes immediately withTypeError: cannot read property 'item' of null(seems related to the error when you run with ngzone).Some things seem to be happening out of order, so when we try to enter Angular’s zone, not everything is ready yet, so it breaks.
Test project with setTimeout: https://play.nativescript.org/?template=play-ng&id=hpl6OJ&v=7
Edit 2:
After giving it some more thought, it seems the loaded event is called just after
ViewUtil.CreateView, while the attributes haven’t even been set yet. Unloaded is called inViewBase._removeView, insideremoveFromVisualTree. This all happens while angular is still rendering and the attributes aren’t set yet. setTimeout with 0 makes the event fire after all the event loop has been processed.So our options probably are either making these events run outside of angular, and it’s up to the developer to use timeouts, or setting the timeout inside the listen which means the event won’t be called in the exact moment it happens (already true for loaded, anyway).
hii @tsonevn , there were no issue with WebImage. i had found problem and solved it. i’m also adding full information if anyone may need it in future.
in above code albumObj is shared service which has “albums” named array. this service initially fetch previous Albums from the local database. and also request fro new albums data and updates it.
i had getting error i had mentioned in previous comment.
above function was real culprit. if i remove the
this.cd.detectChanges()code runs without any error. but doing changeDetection on StackLayouts loaded event and running code i was getting above error and in html file “album” object becomes null. but Note that while logging checking “albumObj.albums” on 100milisecond time interval i can see that it has perfect value and all albums has images property.So in conclusion i can say that when using
this.cd.detectChanges()in StackLayouts loaded event it destroys objects value in html view. but works perfectly in TS file. also i really think there is something wrong “loaded” event or “change Detection Ref” please look into this if possible.