diff --git a/packages/vue-router/src/viewStacks.ts b/packages/vue-router/src/viewStacks.ts index f6d710ccb6..6c86732979 100644 --- a/packages/vue-router/src/viewStacks.ts +++ b/packages/vue-router/src/viewStacks.ts @@ -27,20 +27,7 @@ export const createViewStacks = () => { } const findLeavingViewItemByRouteInfo = (routeInfo: RouteInfo, outletId?: number) => { - return findViewItemByPath(routeInfo.lastPathname, outletId); - } - - const findViewItemByMatchedRoute = (matchedRoute: any, outletId: number): ViewItem | undefined => { - const stack = viewStacks[outletId]; - if (!stack) return undefined; - - return stack.find((viewItem: ViewItem) => { - if (viewItem.matchedRoute.path === matchedRoute.path) { - return viewItem; - } - - return undefined; - }); + return findViewItemByPath(routeInfo.lastPathname, outletId, false); } const findViewItemInStack = (path: string, stack: ViewItem[]): ViewItem | undefined => { @@ -53,7 +40,7 @@ export const createViewStacks = () => { }) } - const findViewItemByPath = (path: string, outletId?: number): ViewItem | undefined => { + const findViewItemByPath = (path: string, outletId?: number, strict: boolean = true): ViewItem | undefined => { const matchView = (viewItem: ViewItem) => { const pathname = path; const viewItemPath = viewItem.matchedRoute.path; @@ -73,8 +60,10 @@ export const createViewStacks = () => { const quickMatch = findViewItemInStack(path, stack); if (quickMatch) return quickMatch; - const match = stack.find(matchView); - if (match) return match; + if (!strict) { + const match = stack.find(matchView); + if (match) return match; + } } else { for (let outletId in viewStacks) { const stack = viewStacks[outletId]; @@ -133,7 +122,6 @@ export const createViewStacks = () => { return { clear, findViewItemByRouteInfo, - findViewItemByMatchedRoute, findLeavingViewItemByRouteInfo, createViewItem, getChildrenToRender, diff --git a/packages/vue/src/components/IonRouterOutlet.ts b/packages/vue/src/components/IonRouterOutlet.ts index ad7bd51cb8..2e03f35396 100644 --- a/packages/vue/src/components/IonRouterOutlet.ts +++ b/packages/vue/src/components/IonRouterOutlet.ts @@ -46,7 +46,19 @@ export const IonRouterOutlet = defineComponent({ // The base url for this router outlet let parentOutletPath: string; - watch(matchedRouteRef, () => setupViewItem(matchedRouteRef)); + watch(matchedRouteRef, (currentValue, previousValue) => { + /** + * We need to make sure that we are not re-rendering + * the same view if navigation changes in a sub-outlet. + * This is mainly for tabs when outlet 1 renders ion-tabs + * and outlet 2 renders the individual tab view. We don't + * want outlet 1 creating a new ion-tabs instance every time + * we switch tabs. + */ + if (currentValue !== previousValue) { + setupViewItem(matchedRouteRef); + } + }); const canStart = () => { const stack = viewStacks.getViewStack(id); @@ -273,19 +285,6 @@ export const IonRouterOutlet = defineComponent({ let enteringViewItem = viewStacks.findViewItemByRouteInfo(currentRoute, id); if (!enteringViewItem) { - /** - * If we have no existing entering item, we need - * make sure that there is no existing view according to the - * matched route rather than what is in the url bar. - * This is mainly for tabs when outlet 1 renders ion-tabs - * and outlet 2 renders the individual tab view. We don't - * want outlet 1 creating a new ion-tabs instance every time - * we switch tabs. - */ - if (viewStacks.findViewItemByMatchedRoute(matchedRouteRef.value, id)) { - return; - } - enteringViewItem = viewStacks.createViewItem(id, matchedRouteRef.value.components.default, matchedRouteRef.value, currentRoute); viewStacks.add(enteringViewItem); } diff --git a/packages/vue/test-app/src/router/index.ts b/packages/vue/test-app/src/router/index.ts index 6035f8aff4..764a7925c3 100644 --- a/packages/vue/test-app/src/router/index.ts +++ b/packages/vue/test-app/src/router/index.ts @@ -45,9 +45,13 @@ const routes: Array = [ component: () => import('@/views/RoutingChild.vue') }, { - path: '/routing/item/:id/view', + path: '/routing/:id', component: () => import('@/views/RoutingParameter.vue') }, + { + path: '/routing/:id/view', + component: () => import('@/views/RoutingParameterView.vue') + }, { path: '/navigation', component: () => import('@/views/Navigation.vue') diff --git a/packages/vue/test-app/src/views/Routing.vue b/packages/vue/test-app/src/views/Routing.vue index 7c911004d6..331da03e64 100644 --- a/packages/vue/test-app/src/views/Routing.vue +++ b/packages/vue/test-app/src/views/Routing.vue @@ -24,8 +24,16 @@ Go to Child Page - - Go to Parameterized Route + + Go to Parameter Page ABC + + + + Go to Parameter Page XYZ + + + + Go to Parameterized Page View diff --git a/packages/vue/test-app/src/views/RoutingParameter.vue b/packages/vue/test-app/src/views/RoutingParameter.vue index 337bb29f07..01d12d235c 100644 --- a/packages/vue/test-app/src/views/RoutingParameter.vue +++ b/packages/vue/test-app/src/views/RoutingParameter.vue @@ -16,8 +16,10 @@ -
- Routing Parameter Page: {{ $route.params.id }} + Go to Single View + +
+ {{ $route.params.id }}
@@ -25,6 +27,7 @@ diff --git a/packages/vue/test-app/tests/e2e/specs/routing.js b/packages/vue/test-app/tests/e2e/specs/routing.js index b65e328133..b77baa2978 100644 --- a/packages/vue/test-app/tests/e2e/specs/routing.js +++ b/packages/vue/test-app/tests/e2e/specs/routing.js @@ -48,19 +48,46 @@ describe('Routing', () => { cy.ionPageDoesNotExist('routingchild') }); - // Verifies fix for https://github.com/ionic-team/ionic-framework/issues/22324 - it('should show correct view when navigating back from parameterized page to query string page', () => { - cy.visit('http://localhost:8080'); - cy.get('#routing').click(); - cy.get('#route-params').click(); - cy.get('#item').click(); + // Verifies fix for https://github.com/ionic-team/ionic-framework/issues/22359 + it('should navigate to multiple pages that match the same parameterized route', () => { + cy.visit('http://localhost:8080/routing'); + cy.get('#parameter-abc').click(); cy.ionPageVisible('routingparameter'); - cy.ionPageHidden('routing'); - + cy.get('[data-pageid=routingparameter] #parameter-value').should('have.text', 'abc'); cy.ionBackClick('routingparameter'); cy.ionPageDoesNotExist('routingparameter'); + + cy.get('#parameter-xyz').click(); + cy.ionPageVisible('routingparameter'); + cy.get('[data-pageid=routingparameter] #parameter-value').should('have.text', 'xyz'); + }); + + // Verifies fix for https://github.com/ionic-team/ionic-framework/issues/22359 + it('should handle parameterized urls properly', () => { + cy.visit('http://localhost:8080/routing'); + + cy.get('#parameter-abc').click(); + cy.ionPageVisible('routingparameter'); + + cy.get('#parameter-view').click(); + + cy.ionPageVisible('routingparameterview'); + }); + + // Verifies fix for https://github.com/ionic-team/ionic-framework/issues/22324 + it('should show correct view when navigating back from parameterized page to query string page', () => { + cy.visit('http://localhost:8080/routing'); + cy.get('#route-params').click(); + cy.get('#parameter-view-item').click(); + + cy.ionPageVisible('routingparameterview'); + cy.ionPageHidden('routing'); + + cy.ionBackClick('routingparameterview'); + + cy.ionPageDoesNotExist('routingparameterview'); cy.ionPageVisible('routing'); });