Here is the work flow of my Ionic app.
App starts with Welcome Page - > Login → Service on background checks for new notification and emits a “new-event” → After login, Home page → New page which is subscribed to “new-event” triggers a change detection.
But I get an error
ViewDestroyedError: Attempt to use a destroyed view: detectChanges
Here is the relevant code.
WelcomePage
login(){
this.auth.login().then(()=>{
this.navCtrl.setRoot('TabsPage');
})
}
TabPage
has default tab as HomePage
which has HeaderComponent
HomePage
ionViewDidLoad(){
this.checkNewNotification().subscribe(()=>{
this.events.publish("new-notification");
})
}
Headercomponent
constructor( public cd: ChangeDetectorRef)
ngOnInit(){
this.events.subscribe('new-notification', () => {
console.log(cd);
this.cd.detectChanges();
})
}
When I login from WelcomePage
to HomePage
and “new-notification” event is fired, the HeaderComponent
fires this.cd.detectChanges()
. But for some reason this throws ViewDestroyedError
.And the error description mentiones welcome.html
. And when I log cd
, the destroyed
attribute is true
.
So my question is why does the ChangeDetectionRef
injected in HeaderComponent
trying to detect changes in WelcomePage
?
Edit
I tried markForChanges
, and it works. Not sure why?
Your subscription outlasts the view. Your code is suspicious because you provide no way to unsubscribe. It ought to look something like this.
eventListener: Subscription = new Subscription();
ngOnInit() {
this.eventListener = this.events.subscribe(...)
}
ngOnDestroy() {
this.eventListener.unsubscribe();
}
and similarly for any other Observables.
It doesn’t matter if you got lucky with markforchanges. You still have ghost Observables haunting your app, and no way to kill them.
The HeaderComponent
is never destroyed. The ChangeDetectionRef
throws error from WelcomePage
template where no ChangeDetectionRef
is injected.
I ignored the fact that part of your post did not make sense. “TabsPage has a HomePage” is a compiler error. I bet if you get clear on the exact relation between the three pages, you’ll know why the view is destroyed.
TabPage
has default tab as HomePage
which has HeaderComponent
. I have edited the part. And I am sure ngDestroy is never fired because I console.log it.
The relation can be simplified as this. The login
action from welcome
page fires an event new-notification
. And welcome
page is destroyed and homepage
which has header
component becomes the view. header
component subscribes to the event, and fires change detection. But for some reason this throws an error ViewDestroyedError
. But this error happens from welcome
page template which is what confusing me.
I’m still not clear on the relationship between WelcomePage and the HeaderCoimponent. But if that’s the only cdr in your code, then what is going on is that it marks part of WelcomePage to be checked, because part of WelcomePage is an OnPush ancestor of HeaderComponent.
There is no onPush strategy or cdr in Welcome page. And it has no connection to header component. Once login is clicked welcome page sets tabs page as root and tabs page has header component. Thats the only connection.
The OnPush strategy is not the same as an OnPush ancestor. navCtrl returns the closest navController. So what is probably happening is that your subscription on WelcomePage doesn’t fire until LoginPage returns the auth, at which point the nav in your subscription is evaluated to refer to one of the navs from your tabs, and maybe not always the same one on every execution. So you end up with a piece from a later page being part of your WelcomePage, which confuses the change detector.
I still don’t understand your structure well, so the exact flow might be different. But the end result if you have pieces from different pages overlapping, and I recommend that you rethink your Observable logic.