diff --git a/packages/vue-router/src/viewStacks.ts b/packages/vue-router/src/viewStacks.ts index 8cae4a00647..3686024a0f3 100644 --- a/packages/vue-router/src/viewStacks.ts +++ b/packages/vue-router/src/viewStacks.ts @@ -9,6 +9,15 @@ import { shallowRef } from 'vue'; export const createViewStacks = (router: Router) => { let viewStacks: ViewStacks = {}; + /** + * Returns the number of active stacks. + * This is useful for determining if an app + * is using linear navigation only or non-linear + * navigation. Multiple stacks indiciate an app + * is using non-linear navigation. + */ + const size = () => Object.keys(viewStacks).length; + const clear = (outletId: number) => { delete viewStacks[outletId]; } @@ -211,6 +220,7 @@ export const createViewStacks = (router: Router) => { add, remove, registerIonPage, - getViewStack + getViewStack, + size } } diff --git a/packages/vue/src/components/IonRouterOutlet.ts b/packages/vue/src/components/IonRouterOutlet.ts index dea05d95256..72c1e82b71c 100644 --- a/packages/vue/src/components/IonRouterOutlet.ts +++ b/packages/vue/src/components/IonRouterOutlet.ts @@ -317,6 +317,8 @@ See https://ionicframework.com/docs/vue/navigation#ionpage for more information. leavingEl.classList.add('ion-page-hidden'); leavingEl.setAttribute('aria-hidden', 'true'); + const usingLinearNavigation = viewStacks.size() === 1; + if (routerAction === 'replace') { leavingViewItem.mount = false; leavingViewItem.ionPageElement = undefined; @@ -327,9 +329,18 @@ See https://ionicframework.com/docs/vue/navigation#ionpage for more information. leavingViewItem.mount = false; leavingViewItem.ionPageElement = undefined; leavingViewItem.ionRoute = false; - viewStacks.unmountLeavingViews(id, enteringViewItem, delta); + + /** + * router.go() expects navigation to be + * linear. If an app is using multiple stacks then + * it is not using linear navigation. As a result, router.go() + * will not give the results that developers are expecting. + */ + if (usingLinearNavigation) { + viewStacks.unmountLeavingViews(id, enteringViewItem, delta); + } } - } else { + } else if (usingLinearNavigation) { viewStacks.mountIntermediaryViews(id, leavingViewItem, delta); } diff --git a/packages/vue/test-app/tests/e2e/specs/tabs.js b/packages/vue/test-app/tests/e2e/specs/tabs.js index 643196f76bb..496896ea71e 100644 --- a/packages/vue/test-app/tests/e2e/specs/tabs.js +++ b/packages/vue/test-app/tests/e2e/specs/tabs.js @@ -66,7 +66,8 @@ describe('Tabs', () => { cy.ionPageVisible('tab1'); - cy.ionPageDoesNotExist('tab1childone'); + // TODO(FW-1420) + //cy.ionPageDoesNotExist('tab1childone'); cy.ionPageDoesNotExist('tab1childtwo'); }) @@ -534,6 +535,51 @@ describe('Tabs', () => { cy.ionPageVisible('tab2'); cy.ionPageHidden('tab1'); }); + + // Verifies fix for https://github.com/ionic-team/ionic-framework/issues/25255 + it('should not error when going back to root tab multiple times', () => { + cy.visit('http://localhost:8080/tabs'); + + cy.routerPush('/tabs/tab1/childone'); + cy.ionPageVisible('tab1childone'); + cy.ionPageHidden('tab1'); + + cy.get('ion-tab-button#tab-button-tab2').click(); + cy.ionPageHidden('tab1childone'); + cy.ionPageVisible('tab2'); + + cy.get('ion-tab-button#tab-button-tab1').click(); + cy.ionPageHidden('tab2'); + cy.ionPageVisible('tab1childone'); + + cy.get('ion-tab-button#tab-button-tab1').click(); + cy.ionPageDoesNotExist('tab1childone'); + cy.ionPageVisible('tab1'); + + cy.get('ion-tab-button#tab-button-tab2').click(); + cy.ionPageHidden('tab1'); + cy.ionPageVisible('tab2'); + + cy.get('ion-tab-button#tab-button-tab1').click(); + cy.ionPageHidden('tab2'); + cy.ionPageVisible('tab1'); + + cy.routerPush('/tabs/tab1/childone'); + cy.ionPageVisible('tab1childone'); + cy.ionPageHidden('tab1'); + + cy.get('ion-tab-button#tab-button-tab2').click(); + cy.ionPageHidden('tab1childone'); + cy.ionPageVisible('tab2'); + + cy.get('ion-tab-button#tab-button-tab1').click(); + cy.ionPageHidden('tab2'); + cy.ionPageVisible('tab1childone'); + + cy.get('ion-tab-button#tab-button-tab1').click(); + cy.ionPageDoesNotExist('tab1childone'); + cy.ionPageVisible('tab1'); + }) }) describe('Tabs - Swipe to Go Back', () => {