diff --git a/packages/vue-router/src/locationHistory.ts b/packages/vue-router/src/locationHistory.ts index 840638de6c..404737d846 100644 --- a/packages/vue-router/src/locationHistory.ts +++ b/packages/vue-router/src/locationHistory.ts @@ -92,16 +92,39 @@ export const createLocationHistory = () => { * and every entry that appears after it. */ const clearHistory = (routeInfo?: RouteInfo) => { - Object.keys(tabsHistory).forEach(key => { - tabsHistory[key] = []; - }); - if (routeInfo) { + + /** + * If there is no route index in locationHistory + * then there will not be any route index in + * tabs either. + */ const existingRouteIndex = locationHistory.findIndex(r => r.position === routeInfo.position); if (existingRouteIndex === -1) return; locationHistory.splice(existingRouteIndex); + + /** + * We also need to search the current tab + * to correctly reset the individual tab + * stack. We should not clear the entire + * tab stack as that means we will lose + * a reference to the root tab route. + */ + const { tab } = routeInfo; + const tabHistory = tabsHistory[tab]; + if (tab && tabHistory) { + const existingTabRouteIndex = tabHistory.findIndex(r => r.position === routeInfo.position); + if (existingTabRouteIndex === -1) return; + + tabsHistory[tab].splice(existingTabRouteIndex); + } + } else { + Object.keys(tabsHistory).forEach(key => { + tabsHistory[key] = []; + }); + locationHistory.length = 0; } } diff --git a/packages/vue-router/src/router.ts b/packages/vue-router/src/router.ts index af23bc7b45..17ded9b25b 100644 --- a/packages/vue-router/src/router.ts +++ b/packages/vue-router/src/router.ts @@ -409,13 +409,22 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) => router.push(routerLink); } - const resetTab = (tab: string, originalHref: string) => { + const resetTab = (tab: string) => { + /** + * Resetting the tab should go back + * to the initial view in the tab stack. + * It should not push a new instance of the + * root tab page onto the stack. + * + * To do this, we get the initial view in the + * tab stack and subtract the position of that + * entry from our current position. From there + * we call router.go() to move us back the + * appropriate number of positions. + */ const routeInfo = locationHistory.getFirstRouteInfoForTab(tab); if (routeInfo) { - const newRouteInfo = { ...routeInfo }; - newRouteInfo.pathname = originalHref; - incomingRouteParams = { ...newRouteInfo, routerAction: 'pop', routerDirection: 'back' }; - router.push({ path: newRouteInfo.pathname, query: parseQuery(newRouteInfo.search) }); + router.go(routeInfo.position - currentHistoryPosition); } } diff --git a/packages/vue/src/components/IonTabButton.ts b/packages/vue/src/components/IonTabButton.ts index 04ae77a126..b80a135475 100644 --- a/packages/vue/src/components/IonTabButton.ts +++ b/packages/vue/src/components/IonTabButton.ts @@ -47,7 +47,7 @@ export const IonTabButton = /*@__PURE__*/ defineComponent({ */ if (prevActiveTab === tab) { if (originalHref !== currentHref) { - ionRouter.resetTab(tab, originalHref); + ionRouter.resetTab(tab); } } else { ionRouter.changeTab(tab, currentHref) diff --git a/packages/vue/test-app/tests/e2e/specs/tabs.js b/packages/vue/test-app/tests/e2e/specs/tabs.js index b5d0cca3fc..e00cc50b8b 100644 --- a/packages/vue/test-app/tests/e2e/specs/tabs.js +++ b/packages/vue/test-app/tests/e2e/specs/tabs.js @@ -51,21 +51,68 @@ describe('Tabs', () => { cy.ionPageHidden('tab1'); }); - it('should return to tab root when clicking tab button', () => { + it('should return to tab root when clicking tab button after going back', () => { cy.visit('http://localhost:8080/tabs') cy.get('#child-one').click(); + cy.ionPageVisible('tab1childone'); + cy.ionPageHidden('tab1'); + cy.get('#child-two').click(); + cy.ionPageHidden('tab1childone'); + cy.ionPageVisible('tab1childtwo'); cy.get('ion-tab-button#tab-button-tab1').click(); cy.ionPageVisible('tab1'); - // TODO this page is not removed - //cy.ionPageDoesNotExist('tab1childone'); + cy.ionPageDoesNotExist('tab1childone'); cy.ionPageDoesNotExist('tab1childtwo'); }) + // Verifies fix for https://github.com/ionic-team/ionic-framework/issues/24934 + it('should return to tab root when clicking tab button', () => { + cy.visit('http://localhost:8080/tabs') + + cy.get('#child-one').click(); + cy.ionPageVisible('tab1childone'); + cy.ionPageHidden('tab1'); + + cy.get('#child-two').click(); + cy.ionPageHidden('tab1childone'); + cy.ionPageVisible('tab1childtwo'); + + cy.ionBackClick('tab1childtwo'); + cy.ionPageVisible('tab1childone'); + cy.ionPageDoesNotExist('tab1childtwo'); + + cy.get('ion-tab-button#tab-button-tab1').click(); + + cy.ionPageVisible('tab1'); + cy.ionPageDoesNotExist('tab1chilone'); + }) + + // Verifies fix for https://github.com/ionic-team/ionic-framework/issues/24934 + it('should return to tab root after replacing history', () => { + cy.visit('http://localhost:8080/tabs') + + cy.get('#child-one').click(); + cy.ionPageVisible('tab1childone'); + cy.ionPageHidden('tab1'); + + cy.get('ion-tab-button#tab-button-tab1').click(); + cy.ionPageVisible('tab1'); + cy.ionPageDoesNotExist('tab1chilone'); + + cy.get('#child-one').click(); + cy.ionPageVisible('tab1childone'); + cy.ionPageHidden('tab1'); + + cy.get('ion-tab-button#tab-button-tab1').click(); + cy.ionPageVisible('tab1'); + cy.ionPageDoesNotExist('tab1chilone'); + }) + it('should be able to create and destroy tabs', () => { cy.visit('http://localhost:8080')