You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Component lifecycles differs on nativescript-angular and angular2 on web. #374
I ran into this problem and I'll try to explain it here.
With nativescript-angular the lifecycle hook ngOnDestroy isn't called when we navigate away from a page as it would be on web. Navigating back reuses the old component with nativescript-angular but a new instance is created on web.
@m-abs You are indeed correct. When doing a page navigation in native app the page/component you are navigation from is not actually destroyed. When you navigate back to it the component is not created again. The original component is shown instead.
Can you please elaborate on you scenario and why this is a problem?
There are also a couple of other ways to plug into the app navigation:
@vakrilov
Thank you for the suggest, I'll try it when I get back to work :)
I'll can try to elaborate, sorry for the long text :)
Our project is based on angular2-seed-advanced, so we share code between the {N} -version and the web-version of our project.
The project is an audiobook-player that shows HTML-content synced to the audio during playback.
We render the HTML-content with our content-viewer-component. On web we use the component as is and in {N} it runs in a small ng2-webapp inside a web-view.
Our page-component sets up events and subscriptions to make this work in our ngOnInit() hook and they’re removed in our ngOnDestroy()hook.
Since the page-component lives on after navigation from it, the subscriptions and events created in ngOnInit() will still be active, this means that the web-view/content-viewer-component still does work that is now unneeded.
We also risk having two instances of the web-view/content-viewer-component running at the same time. If the user navigates to the page again without going back, since that won’t reuse the component.
I also think the behavior goes against what the ng2-docs imply.
In this example, we subscribe to the route params Observable. That implies that the route params can change during the lifetime of this component.
They might. By default, the router reuses a component instance when it re-navigates to the same component type without visiting a different component first. The parameters can change between each re-use.
We can of cause use the Router.events observable as a workaround, but I’d much rather just rely on the hook ng2 components have for it.
I’d also prefer the same behavior (where possible) on both web and in {N}, otherwise it can be surprising for the developers.
Maybe some intermediate approach is when using the paged navigation indicate which is the expected reusability of the components (I would say destroy as default and preserve as alternative).
We are using it in a soon to be launched app and we have already invested too much time with nativescript to go back now. This issue is going to be a dealbreaker. I am willing to help if someone can let me know what do do.
Our designer wants a three tabbed interface, where the navbar is always visible at the bottom of the screen and the user can tap on each tab.
So the user can always forward navigate to any of our three tabs.
The way the router caches pages at the moment and since child-routes doesn't work right on back (see #477) we'll will end up with memory leaks it we don't find a solution.
I've been considering using an JS-hack to work around this by making the components constructor return the first component, but this is not a solution I like.
There're a bunch of problems with this solution, like potentially breaking DI, since the first components injections will always be used. and ngOnInit would get called multiple times.
I've also considered making a private fork of the ns-router that doesn't have caching feature, but I really don't want to maintain it.
Any way to temporarily disable cache folks ? This issue is really the breaking point and we need to launch our app ASAP. Can someone please help out. Thanks in advance
+1 for ng2 lifecycle or additional hooks to determine cache state of page. This would be helpful to subscribe / desubscribe from observables (e.g. if you navigate by observable return on pages, you get hit by race conditions to which page you actually will be navigated).
@tviel You can listen to router.events, you can't use ActivatedRoute, because it seems to stop emitting events after first navigate away from the component...
Could we please make this behavior optional? It makes sense to cache some pages but not others.
This is one of the most annoying "features" of NS Angular and it doesn't seem like anyone's looking to improve it. We've spent so much time debugging issues where resources haven't been released and streams are just piling up because ngOnDestroy is not getting called.
The biggest problem here is inconsistency - the constructor and ngOnInit is getting called every time the component is navigated to. But when navigating out, you're only left with the router event and page unloaded event.
Getting rid of ng events and just using Page events would seem like a good solution but the problem is - the page is unloaded every time app goes to background. Some of the app logic needs to keep running in the background, so this is not a good solution either.
Reacted by Vid, Omi231, seveneye, nickykln, Hoan Vo, yasser, Drew Payment, Mitch Talmadge, Vahid Najafi and Florian Daniel
Closing the issue - for anyone interested in how the native mobile events are working and should be used alongside the Angular ones please read this comment
Reacted by Drew Payment, Alan Neri, aastrouski, Mitch Talmadge and Vahid Najafi
Man, so much for code re-use. Now I have to create an entirely separate tns controller just to use the PageRoute instead of ActivatedRoute. What a joke.
Why if Im writing a wizard, i need to move forward and backward, and sometimes move, skip, or jump to pages/views and limit user capabilities of moving back to pages (i could set a new root here, but not my case) not catched or in any state. Also if i complete the wizard i should be able to ngDestroy all the previous views/pages to do a clean new wizard setup. Current logic is not allowing me to do that, and i do not wanna recreate the wheel or change the native behavior, is there a way to trigger those events or angular cycle hooks (init, destroy, etc) using nativescript?
Activity
vakrilov commentedon Aug 1, 2016
@m-abs You are indeed correct. When doing a page navigation in native app the page/component you are navigation from is not actually destroyed. When you navigate back to it the component is not created again. The original component is shown instead.
Can you please elaborate on you scenario and why this is a problem?
There are also a couple of other ways to plug into the app navigation:
Router.eventsobservablem-abs commentedon Aug 2, 2016
@vakrilov
Thank you for the suggest, I'll try it when I get back to work :)
I'll can try to elaborate, sorry for the long text :)
Our project is based on
angular2-seed-advanced, so we share code between the {N} -version and the web-version of our project.The project is an audiobook-player that shows HTML-content synced to the audio during playback.
We render the HTML-content with our
content-viewer-component. On web we use the component as is and in {N} it runs in a small ng2-webapp inside aweb-view.Our page-component sets up events and subscriptions to make this work in our
ngOnInit()hook and they’re removed in ourngOnDestroy()hook.Since the page-component lives on after navigation from it, the subscriptions and events created in
ngOnInit()will still be active, this means that theweb-view/content-viewer-component still does work that is now unneeded.We also risk having two instances of the
web-view/content-viewer-component running at the same time. If the user navigates to the page again without going back, since that won’t reuse the component.I also think the behavior goes against what the ng2-docs imply.
From: https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html#!#hooks-overview
From: https://angular.io/docs/ts/latest/guide/router.html#!#route-parameters
We can of cause use the
Router.eventsobservable as a workaround, but I’d much rather just rely on the hook ng2 components have for it.I’d also prefer the same behavior (where possible) on both web and in {N}, otherwise it can be surprising for the developers.
I can see it’s done intentionally here: https://github.com/NativeScript/nativescript-angular/blob/master/nativescript-angular/router/page-router-outlet.ts#L112
And I do understand the benefits of caching components like that, but what about larger app with many pages where the user don’t necessarily navigates back?
Don't we risk it accumulates old components and thus causing the leaks the ng2-docs mention?
dvabuzyarov commentedon Aug 26, 2016
+1
ignaciolarranaga commentedon Sep 23, 2016
Maybe some intermediate approach is when using the paged navigation indicate which is the expected reusability of the components (I would say destroy as default and preserve as alternative).
sivsushruth commentedon Sep 27, 2016
Any updates on this ? Very urgent!
sivsushruth commentedon Sep 29, 2016
We are using it in a soon to be launched app and we have already invested too much time with nativescript to go back now. This issue is going to be a dealbreaker. I am willing to help if someone can let me know what do do.
m-abs commentedon Sep 29, 2016
Our designer wants a three tabbed interface, where the navbar is always visible at the bottom of the screen and the user can tap on each tab.
So the user can always forward navigate to any of our three tabs.
The way the router caches pages at the moment and since child-routes doesn't work right on back (see #477) we'll will end up with memory leaks it we don't find a solution.
I've been considering using an JS-hack to work around this by making the components constructor return the first component, but this is not a solution I like.
There're a bunch of problems with this solution, like potentially breaking DI, since the first components injections will always be used. and ngOnInit would get called multiple times.
I've also considered making a private fork of the ns-router that doesn't have caching feature, but I really don't want to maintain it.
sivsushruth commentedon Oct 6, 2016
Any way to temporarily disable cache folks ? This issue is really the breaking point and we need to launch our app ASAP. Can someone please help out. Thanks in advance
m-abs commentedon Oct 6, 2016
@sivsushruth
If you use a
router-outletand managed back-buttons yourself, pages aren't cached. (Since it's not a NativeScript Page switch).m-abs commentedon Oct 6, 2016
@sivsushruth
Unfortunately you need to capture back-button on android (like this: https://github.com/m-abs/angular2-seed-advanced/blob/child-router-android-back-button/nativescript/app/pages/app/app.component.ts#L58-L69) and add your own NavigationButton to the ActionBar.
sivsushruth commentedon Oct 6, 2016
@m-abs The issue however is, I need caching for a few pages, is it possible to have router-outlet inside page-router-outlet ?
m-abs commentedon Oct 6, 2016
@sivsushruth
That's what we do.
We've created a few child routes like this: https://github.com/m-abs/angular2-seed-advanced/blob/child-router-android-back-button/src/client/app/components/home/home.routes.ts
And since we're using child-routes, we needed to add an
router-outletto our HomeComponent: https://github.com/m-abs/angular2-seed-advanced/blob/child-router-android-back-button/src/client/app/components/home/home.component.tns.html#L23Routes under
/home/in our example are not cached.tviel commentedon Oct 17, 2016
+1 for ng2 lifecycle or additional hooks to determine cache state of page. This would be helpful to subscribe / desubscribe from observables (e.g. if you navigate by observable return on pages, you get hit by race conditions to which page you actually will be navigated).
m-abs commentedon Oct 22, 2016
@tviel You can listen to router.events, you can't use ActivatedRoute, because it seems to stop emitting events after first navigate away from the component...
Could we please make this behavior optional? It makes sense to cache some pages but not others.
3 remaining items
phattranky commentedon Apr 8, 2017
@m-abs
Thanks :D
So great, use loadedEvent, unloadedEvenet to call ngOnInit and ngOnDestroy solved all problems
bunnyvishal6 commentedon Jun 15, 2017
Awesome! Page.unloadedEvent on ngOnInit solved my problem. @m-abs Thanks alot.
nicodemuz commentedon Jul 1, 2017
It still doesn't work for me. Any idea where I'm doing wrong?
@bunnyvishal6 @m-abs able to help?
m-abs commentedon Jul 1, 2017
@MrNicodemuz
I think the problem is you don't call ngOnInit() after you change the id. So you don't load the new data.
Sent from my OnePlus ONEPLUS A3003 using FastHub
nicodemuz commentedon Jul 1, 2017
@m-abs many thanks it's working now! :)
jdnichollsc commentedon Nov 14, 2017
@m-abs @gergderkson Guys, my app is closed after call
this.ngOnDestroy();Any help is really appreciated
evertonrobertoauler commentedon Jul 25, 2018
Hi, I solved the issue, triggering change detection in my root component, every time any navigation ends.
jnorkus commentedon Oct 16, 2018
This is one of the most annoying "features" of NS Angular and it doesn't seem like anyone's looking to improve it. We've spent so much time debugging issues where resources haven't been released and streams are just piling up because ngOnDestroy is not getting called.
The biggest problem here is inconsistency - the constructor and ngOnInit is getting called every time the component is navigated to. But when navigating out, you're only left with the router event and page unloaded event.
Getting rid of ng events and just using Page events would seem like a good solution but the problem is - the page is unloaded every time app goes to background. Some of the app logic needs to keep running in the background, so this is not a good solution either.
NickIliev commentedon Jan 8, 2019
Closing the issue - for anyone interested in how the native mobile events are working and should be used alongside the Angular ones please read this comment
stanporubin commentedon Sep 26, 2019
I wrote an article about this. I solved it in generic way with the decorator.
MitchTalmadge commentedon Jan 27, 2020
Man, so much for code re-use. Now I have to create an entirely separate tns controller just to use the
PageRouteinstead ofActivatedRoute. What a joke.flodaniel commentedon Aug 10, 2020
This remains a major limitation / "feature" :/
aosi87 commentedon Oct 12, 2020
Why if Im writing a wizard, i need to move forward and backward, and sometimes move, skip, or jump to pages/views and limit user capabilities of moving back to pages (i could set a new root here, but not my case) not catched or in any state. Also if i complete the wizard i should be able to ngDestroy all the previous views/pages to do a clean new wizard setup. Current logic is not allowing me to do that, and i do not wanna recreate the wheel or change the native behavior, is there a way to trigger those events or angular cycle hooks (init, destroy, etc) using nativescript?