ionic-framework: [4.0.0-rc.0] ion-tabs lifecycle events not working when navigating back from another view

Bug Report

Ionic version: [x] 4.x

Current behavior: I have some items/cards on my tab pages and navigate to other pages when I click on them. When I go back to the tabs pages from those views, my lifecycle events like ionViewDidEnter() do not fire. They fire when I’m changing tabs, but when I am coming from a non-tab view, they never fire.

Expected behavior: For these lifecycle events to fire.

Steps to reproduce: Create a tab project, navigate to another view from a tab page that isn’t another tab, go back to the tab page and see that they have not fired.

Ionic info:

Ionic:

   ionic (Ionic CLI)             : 4.6.0 (/usr/lib/node_modules/ionic)
   Ionic Framework               : @ionic/angular 4.0.0-rc.0
   @angular-devkit/build-angular : 0.10.7
   @angular-devkit/schematics    : 7.1.2
   @angular/cli                  : 7.1.2
   @ionic/angular-toolkit        : 1.2.1

Cordova:

   cordova (Cordova CLI) : not installed
   Cordova Platforms     : not available
   Cordova Plugins       : not available

System:

   NodeJS : v8.14.0 (/usr/bin/node)
   npm    : 6.4.1
   OS     : Linux 4.18

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 10
  • Comments: 42 (11 by maintainers)

Commits related to this issue

Most upvoted comments

Hi everyone,

I wanted to provide an update regarding the status of this issue. After discussing with the team, we have determined this is not a bug in Ionic Framework; however, we realize there are valid use cases in which developers may want to listen for lifecycle events on an individual tab. Due to this, we have provided a temporary workaround as well as plans for further development.

Why is this not a bug?

When pages transition in Ionic Framework, they fire lifecycle events. For example, going from /page1 to /page2 would fire ionViewWillLeave and ionViewDidLeave events on the Page1 component and ionViewWillEnter and ionViewDidEnter events on the Page2 component. The same logic applies when going from /tabs/tab1 to /tabs/tab2. In both of these scenarios, we are staying within the same parent ion-router-outlet context.

The reported issue occurs when navigating between ion-router-outlet contexts. In this case, we are seeing it when navigating from /tabs/tab1 to /page2. When this transition happens, Tab1 remains the active tab, and the entire tabs context transitions away. As a result, lifecycle events will fire on the root TabsPage component, but not on Tab1.

For many users, this is unexpected because Tab1 visually appears to transition away. However, under the hood, the entire tabs context transitions away.

What is the workaround?

Luckily, there is an easy to use workaround for developers who wish to listen for lifecycle events on individual tab pages:

tabs.page.html

<ion-tabs #tabs (ionTabsDidChange)="tabChange(tabs)">
  ...
</ion-tabs>

tabs.page.ts

import { Component } from '@angular/core';
import { IonTabs } from '@ionic/angular'

@Component({
  selector: 'app-tabs',
  templateUrl: 'tabs.page.html',
  styleUrls: ['tabs.page.scss']
})
export class TabsPage {
  private activeTab?: HTMLElement;

  constructor() {}
  
  tabChange(tabsRef: IonTabs) {
    this.activeTab = tabsRef.outlet.activatedView.element;
  }

  ionViewWillLeave() {
    this.propagateToActiveTab('ionViewWillLeave');
  }
  
  ionViewDidLeave() {
    this.propagateToActiveTab('ionViewDidLeave');
  }
  
  ionViewWillEnter() {
    this.propagateToActiveTab('ionViewWillEnter');
  }
  
  ionViewDidEnter() {
    this.propagateToActiveTab('ionViewDidEnter');
  }
  
  private propagateToActiveTab(eventName: string) {    
    if (this.activeTab) {
      this.activeTab.dispatchEvent(new CustomEvent(eventName));
    }
  }
}

In this example we do 2 things:

  1. We keep track of the active tab element via ionTabsDidChange.
  2. We listen for lifecycle events on the root tabs component and propagate them to the active tab (if one exists).

In current versions of Ionic Framework, you will get a warning that activatedView is private and only accessible from within IonRouterOutlet. Once Ionic Framework v5.2.0 ships you will be able to access this without receiving the warning. For now, you can do (tabsRef.outlet as any).activatedView.element to bypass this warning.

Future Work

For future major releases of Ionic Framework, we are investigating bringing Ionic Angular routing closer to what Ionic React does. This would involve each Ionic page having a root ion-page component, not including the root tabs page. Lifecycle events would be dispatched on these components.

With this approach, the router sees a page transitioning in and a page transitioning out but does not care which router outlet each page is part of.

This would be a breaking change in Ionic Angular as the root tab page would no longer fire lifecycle events. Please note that this has not been finalized, and the implementation details may change. We are actively discussing the best way to do this while weighing the pros and cons of the implementation.

Please let me know if there are any questions. For any additional bugs, please open a new issue. Thank you!

Hi there,

Thanks for all the feedback so far! I have pushed a new nightly build that fixes this issue. npm i @ionic/angular@4.4.1-dev.201905212016.fb63a6f

Perfect you solved all of my use cases. cheer

Still not working in 5.0.7.

Hi everyone,

I am working on a fix for this issue and have released a nightly build of Ionic (npm i @ionic/angular@4.4.1-dev.201905211329.682f163). It would be great if some people could test it out with their use cases and provide some feedback.

We appreciate your patience as we work to resolve this issue. Thanks!

NOT WORKING!!!

Hi all,

@liamdebeasi any updates on that topic? It is still present in 5.0.4

My current workaround looks like the following:

Create an interface with the hooks you want to be implemented in your child tabs

tab.ts

export interface Tab {
  tabsWillEnter();
  tabsDidEnter();
  tabsWillLeave();
  tabsDidLeave();
}

Listen to tab changes and lifecycle hooks in your parent tab and forward them to your child tabs

tabs.page.html

<ion-tabs #tabs>
...
</ion-tabs>

tabs.page.ts

export class TabsPage implements OnInit, OnDestroy {

  @ViewChild('tabs', { static: true }) tabs: IonTabs;
  private subs = new Subscription();
  private currentTab: Tab;
  private tabsDidEnter = false;

  constructor() { }

  ngOnInit() {
    const tabSub = this.tabs.ionTabsDidChange.subscribe(() => {
      this.currentTab = this.tabs.outlet.component as Tab;
    });
    this.subs.add(tabSub);
  }

  ionViewWillEnter() {
    if (this.tabsDidEnter) { // Do not fire on initial load - ionViewWillEnter of child tab will fire
      this.currentTab.tabsWillEnter(); 
    }
  }

  ionViewDidEnter() {
    if (this.tabsDidEnter) { // Do not fire on initial load - ionViewDidEnter of child tab will fire
      this.currentTab.tabsDidEnter(); 
    }
    this.tabsDidEnter = true;
  }

  ionViewWillLeave() {
    this.currentTab.tabsWillLeave();
  }

  ionViewDidLeave() {
    this.currentTab.tabsDidLeave();
  }

  ngOnDestroy() {
    this.subs.unsubscribe();
  }

}

Implement the Tab interface into your child tabs

tab1.page.ts

export class Tab1Page implements Tab {

  constructor() {}

  ionViewWillEnter() { }
  ionViewDidEnter() { }
  ionViewWillLeave() { }
  ionViewDidLeave() { }

  tabsWillEnter() { }
  tabsDidEnter() { }
  tabsWillLeave() { }
  tabsDidLeave() { }

}

Hi everyone,

This has not been included in the latest release. The PR that’s up currently does not address the root issue (which is that nested router outlets cause problems with lifecycle hooks). I am going to be discussing this issue with the team soon.

Thanks!

The compile warnings are gone now. thumbsup

However the back link issue still persisted.

%3D becomes %253D. Some text escape issue maybe? This also messes with going back if I had query parameters: /adventures/adventures?category=PROJECT becomes /adventures%3Fcategory%3DPROJECT

Hmm sounds like a weird dev build. I’ll try to push another one out. Thanks! Glad the main issue is resolved at least!

Thank you @liamdebeasi. I will test it later today and post my feedback.

@brandyscarney thank you. There are 10-20 tickets related to this problem already. And since last year. Hope you can fix it soon.

Any update on this??? I have the same issue. When I am coming back to a page with

mainThis.navCtrl.navigateForward('/tabs/tab2?rand='+random);

ionViewDidEnter does not fire .

@rikenpatel20 doesn’t work in a tabbed view though 😦