ViewDestroyed error when change detection done on an active component

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.