Ionic version:
[ ] 1.x
[x] 2.x
I'm submitting a ...
[x] bug report
[ ] feature request
[ ] support request
Current behavior:
The ionViewWillLeave and ionViewDidLeave lifecycle events do not fire when navigating using the side menu.
Expected behavior:
The events to be fired when navigating with the side menu.
Steps to reproduce:
Download a fresh copy of the ionic conference app. Add the below code to schedule.ts. Note that these events are only being picked up when navigating with the tabs, they don't get picked up when navigating with the side menu.
Related code:
ionViewWillLeave () {
console.log( 'view will leave' );
}
ionViewDidLeave () {
console.log( 'view did leave' );
}
Other information:
Ionic info:
Cordova CLI: 6.4.0
Ionic Framework Version: 2.0.0-rc.4
Ionic CLI Version: 2.1.17
Ionic App Lib Version: 2.1.7
Ionic App Scripts Version: 0.0.47
ios-deploy version: 1.9.0
ios-sim version: 5.0.11
OS: macOS Sierra
Node Version: v7.0.0
Xcode version: Xcode 8.1 Build version 8B62
I just tried this and can confirm. Looks like a bug to me.
These hooks are triggering correctly when navigating from the side menu:
ionViewDidLoad
ionViewWillEnter
ionViewDidEnter
These ones are not:
ionViewWillLeave
ionViewDidLeave
I did some more testing and it looks like there's a few more issues.
ionViewCanEnter
only triggers when navigating from the side menu, but not from the tabsionViewCanLeave
never triggers, neither from the side menu nor from the tabsTested with the latest nightly (2.0.0-rc.4-201701101946), same behavior.
To summarize:
| Lifecycle hook | Tabs | Side menu |
| ---------------- | ----- | ------------ |
| ionViewDidLoad | โ
| โ
|
| ionViewWillEnter | โ
| โ
|
| ionViewDidEnter | โ
| โ
|
| ionViewWillLeave | โ
| โ |
| ionViewDidLeave | โ
| โ |
| ionViewWillUnload | โ
| โ
|
| ionViewCanEnter | โ | โ
|
| ionViewCanLeave | โ | โ |
Hello @jsayol , are you testing this on a device or in the browser? I unfortunately cannot reproduce this in the conf app or with our e2e tests.
Hi @jgw96 . I've just tested this in both the browser and the sim and can recreate it in both environments. I'm testing on an iPad Retina in the Sim and my browser is Chrome (running this on macOS Sierra).
@jgw96 for reference this is the exact code I am using in schedule.ts in the ionic conference app to test the issue. (the rest of the app is untouched and I downloaded a fresh copy from GitHub a few hours ago).
In this setup I'm seeing the issue when navigating away from the schedule page using the side menu.
````
constructor(
public alertCtrl: AlertController,
public app: App,
public loadingCtrl: LoadingController,
public modalCtrl: ModalController,
public navCtrl: NavController,
public confData: ConferenceData,
public user: UserData,
public toastController: ToastController
) {}
ionViewDidLoad() {
console.log( 'view did load' );
this.app.setTitle('Schedule');
this.updateSchedule();
}
ionViewWillEnter () {
console.log( 'view will enter' );
}
ionViewDidEnter () {
console.log( 'view did enter' );
}
ionViewWillLeave () {
console.log( 'view will leave' );
}
ionViewDidLeave () {
console.log( 'view did leave' );
}
ionViewWillUnload () {
console.log( 'view will unload' );
}
ionViewCanEnter () {
console.log( 'view can enter' );
}
````
Hey @jgw96, I was testing it on the browser (Chrome 55.0.2883). My setup looked basically like what @samhcorney just showed.
@jsayol Thanks for the info, i am now able to reproduce. This one is a little tricky to repro and weirdly enough does not fail in any of our karma tests around the NavController.
actually @jsayol can you try this with rc5? I actually cant repro in rc5
@jgw96 I just git cloned a brand new copy of the conference app, which has already been updated to RC5, and I'm still seeing the same behavior.
These are the only changes I made to test this:
$ git diff schedule.ts
diff --git a/src/pages/schedule/schedule.ts b/src/pages/schedule/schedule.ts
index e17c848..19fd891 100644
--- a/src/pages/schedule/schedule.ts
+++ b/src/pages/schedule/schedule.ts
@@ -44,10 +44,36 @@ export class SchedulePage {
) {}
ionViewDidLoad() {
+ console.info('ionViewDidLoad');
this.app.setTitle('Schedule');
this.updateSchedule();
}
+ ionViewWillEnter() {
+ console.info('ionViewWillEnter');
+ }
+
+ ionViewDidEnter() {
+ console.info('ionViewDidEnter');
+ }
+ ionViewWillLeave() {
+ console.info('ionViewWillLeave');
+ }
+ ionViewDidLeave() {
+ console.info('ionViewDidLeave');
+ }
+ ionViewWillUnload() {
+ console.info('ionViewWillUnload');
+ }
+ ionViewCanEnter() {
+ console.info('ionViewCanEnter');
+ return true;
+ }
+ ionViewCanLeave() {
+ console.info('ionViewCanLeave');
+ return true;
+ }
+
updateSchedule() {
// Close any open sliding items when the schedule updates
this.scheduleList && this.scheduleList.closeSlidingItems();
And just in case:
$ ionic info
Your system information:
Cordova CLI: 6.4.0
Ionic Framework Version: 2.0.0-rc.5
Ionic CLI Version: 2.1.18
Ionic App Lib Version: 2.1.7
Ionic App Scripts Version: 1.0.0
ios-deploy version: Not installed
ios-sim version: Not installed
OS: Linux 4.8
Node Version: v7.4.0
Xcode version: Not installed
@jsayol alright, thanks for the testing with me on this! So maybe im misunderstanding here, when logging all those lifecycle events on the schedule page, do the appropriate ones such as didLoad and canEnter get fired when you first load the app?
On first loading I see these hooks triggering:
So far, so good. The problem appears when navigating using either the tabs or the side menu.
For example, reload the app (the 4 hooks I just told you will trigger) and then navigate to a different page using the side menu. When you do that there should be 3 hooks triggering for the Schedule page:
but none of them are triggering.
Ah, @jgw96 I think I know what's going on. When navigating using the tabs, the current page gets poped and the new one gets pushed so everything works correctly (except for ionViewCanEnter which only triggers when loading the view, and ionViewCanLeave which never triggers as far as I can tell).
On the other hand, navigating using the side menu actually calls setRoot to TabsPage with tabIndex set to the new page, so ionViewWillLeave and ionViewDidLeave only trigger for TabsPage, not for the actual page selected inside.
Edit: That's how the conference app implements the side menu so I'm not sure if this is actually an issue or just the expected behavior.
@jsayol ahh just ahead of me in typing that haha (: So you are 100% correct here. Honestly, this is kinda confusing though so im checking with the rest of the team on exactly what the behavior of the lifecycle events should be in this situation. In a literal sense, they are working exactly like they should, but since its slightly confusing at first i want to make sure this is how we want them working. Again, just want to say thanks for testing all this with me and standing all my questions!
Cool!
There's still definitely a problem with ionViewCanEnter
and ionViewCanLeave
, though.
ionViewCanEnter
: Only triggers once, right before loading the component (before ionViewDidLoad
). Never triggers again when the view enters (before ionViewWillEnter
).ionViewCanLeave
: Never triggers (before ionViewWillLeave
) when navigating with the tabs. Works OK when using setRoot.The current implementation of ionViewCanEnter
and ionViewCanLeave
would make sense if they were instead called ionViewCanLoad
and ionViewCanUnload
.
Edit: this should probably go on a separate issue so that this one can be closed as soon as things get cleared up.
Back to the original issue, the alternative would be to trigger the relevant lifecycle hooks on any child views and not just on the one being acted upon.
For example, if an ionViewWillLeave
triggers for TabsPage then it should also trigger for the page of the currently selected tab. I'm not sure if this could cause any problems, though, but it's worth exploring.
Hello @jsayol sorry for the lack of a reply on this lately, been very busy here at Ionic. So for this comment https://github.com/driftyco/ionic/issues/9951#issuecomment-272035391: ionViewCanEnter
is only firing once because the tabs view is actually only loading in once. ionViewDidLoad
also only fires once for the first tab because of the same reason. ionViewCanLeave
also only fires once because the tabs view does not actually leave. By setting root your reloading the nav stack which then makes it fire because the earlier nav stack is actually leaving at that time. I agree with you that renaming them might be a good solution here but as it sits now the lifecycle events are working as they should. Also, for the record, the way navigation happens in the conference app is a little weird compared to 90% of the ionic apps out there, which is one of the reasons that the way lifecycle events work in the conf app is a little confusing at first. Because the lifecycle events are working as they should I am going to close this issue for now, but i definitely think the discussion should continue on renaming some of the lifecycle events in the other issue you opened. Thanks for using Ionic!
Hi Team,
Working on side menu, as user login in via facebook, in the side menu user detail like name and pic should be display. but ionViewCanEnter() seems not working here (app.component) please help.. my code...
`import { NativeStorage } from '@ionic-native/native-storage';
import { Facebook } from '@ionic-native/facebook';
@Component({
templateUrl: 'app.html'
})
export class MyApp {
@ViewChild(Nav) nav: Nav;
rootPage: any;
pages: Array<{title: string, component: any}>;
user: any;
userReady: boolean = false;
constructor(public fb: Facebook, public nativeStorage: NativeStorage, public platform: Platform, public statusBar: StatusBar, public splashScreen: SplashScreen) {
this.initializeApp();
// used for an example of ngFor and navigation
this.pages = [
{ title: 'Home', component: HomePage },
{ title: 'List', component: ListPage }
];
}
ionViewCanEnter(){
let env = this;
this.nativeStorage.getItem('user')
.then(function (data){
env.user = {
name: data.name,
gender: data.gender,
picture: data.picture
};
env.userReady = true;
}, function(error){
console.log(error);
});
}
initializeApp() {
this.platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
let env = this;
this.nativeStorage.getItem('user')
.then( function (data) {
// user is previously logged and we have his data
// we will let him access the app
env.nav.push(HomePage);
env.splashScreen.hide();
}, function (error) {
//we don't have the user data so we will ask him to log in
env.nav.push(LoginPage);
env.splashScreen.hide();
});
this.statusBar.styleDefault();
});
}
openPage(page) {
// Reset the content nav to have just this page
// we wouldn't want the back button to show in this scenario
this.nav.setRoot(page.component);
}
}
`
It would be helpful to add this to the documentation: "if an ionViewWillLeave
triggers for TabsPage [it is designed to not] trigger for the page of the currently selected tab". I understand this is because <ion-tab>
's [root]
creates a separate navCtrl stack from its Tabs container's navCtrl stack. What is the recommended way of triggering ionViewWillLeave
for the tab if the tab's stack is length 1 (cannot use .pop()
)?
Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.
Most helpful comment
Tested with the latest nightly (2.0.0-rc.4-201701101946), same behavior.
To summarize:
| Lifecycle hook | Tabs | Side menu |
| ---------------- | ----- | ------------ |
| ionViewDidLoad | โ | โ |
| ionViewWillEnter | โ | โ |
| ionViewDidEnter | โ | โ |
| ionViewWillLeave | โ | โ |
| ionViewDidLeave | โ | โ |
| ionViewWillUnload | โ | โ |
| ionViewCanEnter | โ | โ |
| ionViewCanLeave | โ | โ |