From f09c300b0a7af708ed3c405952f6155c96092e73 Mon Sep 17 00:00:00 2001 From: "Manu Mtz.-Almeida" Date: Tue, 6 Dec 2016 14:11:18 +0100 Subject: [PATCH] fix(tabs): current tab still active if selected tab does not have a root The current selected tab should NOT be deselected (i.e. detached from change detection) if the selected tab does not have a root ie. a tab that acts as a button to open a modal, logout etc. Lifecycle events should not be dispatched either. Right now we are dispatching willLeave/willEnter always (this is a bug). Closes #9392. Closes #9811. Closes #9392. --- src/components/tabs/tabs.ts | 85 +++++++++++-------- .../tabs/test/advanced/app-module.ts | 46 +++++++++- .../tabs/test/advanced/tab1page1.html | 2 + src/components/tabs/test/advanced/tabs.html | 1 + 4 files changed, 96 insertions(+), 38 deletions(-) diff --git a/src/components/tabs/tabs.ts b/src/components/tabs/tabs.ts index 985ce11be79..3eec7ea1114 100644 --- a/src/components/tabs/tabs.ts +++ b/src/components/tabs/tabs.ts @@ -374,54 +374,69 @@ export class Tabs extends Ion implements AfterViewInit { return; } - const deselectedTab = this.getSelected(); - if (selectedTab === deselectedTab) { - // no change + // If the selected tab is the current selected tab, we do not switch + const currentTab = this.getSelected(); + if (selectedTab === currentTab) { return this._touchActive(selectedTab); } - let deselectedPage: ViewController; - if (deselectedTab) { - deselectedPage = deselectedTab.getActive(); - deselectedPage && deselectedPage._willLeave(false); + // If the selected tab does not have a root, we do not switch (#9392) + // it's possible the tab is only for opening modal's or signing out + // and doesn't actually have content. In the case there's no content + // for a tab then do nothing and leave the current view as is + if (!selectedTab.root) { + selectedTab.ionSelect.emit(selectedTab); + this.ionChange.emit(selectedTab); + return; } - opts.animate = false; + // At this point we are going to perform a page switch + // Let's fire willLeave in the current tab page + let currentPage: ViewController; + if (currentTab) { + currentPage = currentTab.getActive(); + currentPage && currentPage._willLeave(false); + } + // Fire willEnter in the new selected tab const selectedPage = selectedTab.getActive(); selectedPage && selectedPage._willEnter(); - selectedTab.load(opts, (alreadyLoaded: boolean) => { - selectedTab.ionSelect.emit(selectedTab); - this.ionChange.emit(selectedTab); + // Let's start the transition + opts.animate = false; + selectedTab.load(opts, () => { + if (opts.updateUrl !== false) { + this._linker.navChange(DIRECTION_SWITCH); + } + this._tabSwitchEnd(selectedTab, selectedPage, currentPage); + }); + } - if (selectedTab.root) { - // only show the selectedTab if it has a root - // it's possible the tab is only for opening modal's or signing out - // and doesn't actually have content. In the case there's no content - // for a tab then do nothing and leave the current view as is - this._tabs.forEach(tab => { - tab.setSelected(tab === selectedTab); - }); - - if (this.tabsHighlight) { - this._highlight.select(selectedTab); - } + _tabSwitchEnd(selectedTab: Tab, selectedPage: ViewController, currentPage: ViewController) { + selectedTab.ionSelect.emit(selectedTab); + this.ionChange.emit(selectedTab); - if (opts.updateUrl !== false) { - this._linker.navChange(DIRECTION_SWITCH); - } - } + // Update tabs selection state + const tabs = this._tabs; + let tab: Tab; + for (var i = 0; i < tabs.length; i++) { + tab = tabs[i]; + tab.setSelected(tab === selectedTab); + } + + if (this.tabsHighlight) { + this._highlight.select(selectedTab); + } - selectedPage && selectedPage._didEnter(); - deselectedPage && deselectedPage._didLeave(); + // Fire didEnter/didLeave lifecycle events + selectedPage && selectedPage._didEnter(); + currentPage && currentPage._didLeave(); - // track the order of which tabs have been selected, by their index - // do not track if the tab index is the same as the previous - if (this._selectHistory[this._selectHistory.length - 1] !== selectedTab.id) { - this._selectHistory.push(selectedTab.id); - } - }); + // track the order of which tabs have been selected, by their index + // do not track if the tab index is the same as the previous + if (this._selectHistory[this._selectHistory.length - 1] !== selectedTab.id) { + this._selectHistory.push(selectedTab.id); + } } /** diff --git a/src/components/tabs/test/advanced/app-module.ts b/src/components/tabs/test/advanced/app-module.ts index 99d0805b27c..3259c446615 100644 --- a/src/components/tabs/test/advanced/app-module.ts +++ b/src/components/tabs/test/advanced/app-module.ts @@ -1,5 +1,5 @@ import { Component, NgModule, ViewChild } from '@angular/core'; -import { /*DeepLink,*/ DeepLinkConfig, IonicApp, IonicModule, App, NavController, NavParams, ModalController, ViewController, Tabs, Tab } from '../../../..'; +import { /*DeepLink,*/AlertController, DeepLinkConfig, IonicApp, IonicModule, App, NavController, NavParams, ModalController, ViewController, Tabs, Tab } from '../../../..'; // @DeepLink({ name: 'sign-in' }) @@ -35,7 +35,12 @@ export class TabsPage { @ViewChild(Tabs) tabs: Tabs; - constructor(public modalCtrl: ModalController, public params: NavParams) {} + constructor( + public navCtrl: NavController, + public modalCtrl: ModalController, + public params: NavParams, + public alertCtrl: AlertController + ) { } ngAfterViewInit() { this.tabs.ionChange.subscribe((tab: Tab) => { @@ -51,6 +56,39 @@ export class TabsPage { console.log('onTabChange'); } + logout() { + this.navCtrl.pop().catch(() => { + console.log('Cannot go back.'); + }); + } + + ionViewCanLeave() { + return new Promise((resolve, reject) => { + let alert = this.alertCtrl.create({ + title: 'Log out', + subTitle: 'Are you sure you want to log out?', + buttons: [ + { + text: 'No', + role: 'cancel', + handler: () => { + reject(); + } + }, + { + text: 'Yes', + handler: () => { + alert.dismiss().then(() => { + resolve(); + }); + } + } + ] + }); + alert.present(); + }); + } + chat() { console.log('Chat clicked!'); this.modalCtrl.create(ChatPage).present(); @@ -104,7 +142,9 @@ export class Tab1Page1 { } logout() { - this.app.getRootNav().setRoot(SignIn, null, { animate: true, direction: 'back' }); + this.app.getRootNav().setRoot(SignIn, null, { animate: true, direction: 'back' }).catch(() => { + console.debug('logout cancelled'); + }); } ionViewWillEnter() { diff --git a/src/components/tabs/test/advanced/tab1page1.html b/src/components/tabs/test/advanced/tab1page1.html index 91dc13ff845..e48af4ddfcc 100644 --- a/src/components/tabs/test/advanced/tab1page1.html +++ b/src/components/tabs/test/advanced/tab1page1.html @@ -13,6 +13,8 @@

+

+

"Change color" should continue working after clicking Logout in the tabbar and cancelling (No in the alert)

UserId: {{userId}}

diff --git a/src/components/tabs/test/advanced/tabs.html b/src/components/tabs/test/advanced/tabs.html index a64ce743457..95ab12e88f0 100644 --- a/src/components/tabs/test/advanced/tabs.html +++ b/src/components/tabs/test/advanced/tabs.html @@ -4,4 +4,5 @@ +