Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: IonRouter's navigate() pop/back not working after displaying more than 2 ion-tab pages #27443

Closed
3 tasks done
fcamblor opened this issue May 10, 2023 · 6 comments
Closed
3 tasks done
Labels

Comments

@fcamblor
Copy link

Prerequisites

Ionic Framework Version

v7.x

Current Behavior

In a Non-Linear Routing scenario, when I navigate to a tabbed view, then navigate on multiple tabs, I'm not able to pop the tabbed view from the history as soon as I switched to more than 2 different tabs (if I switch between 2 tabs, I'm not facing any issue)

This can be pinpointed by following video

  • Following navigation is ✅ :
    [event-selector]
    --(select event | push)--> [event schedule]
    --(back button clicked | pop) --> [event-selector]

  • Following navigation is ✅ too :
    [event-selector]
    --(select event | push)--> [event schedule]
    --(switch on tab favorites | ??? (not sure if push or replace)) --> [event favorites]
    --(back button clicked | pop) --> [event-selector]

  • Now, if I had a third tab navigation, it is failing ❌ :
    [event-selector]
    --(select event | push)--> [event schedule]
    --(switch on tab favorites | ??? (not sure if push or replace)) --> [event favorites]
    --(switch on tab feedback | ??? (not sure if push or replace)) --> [event feedbacks]
    --(back button clicked | pop) -->[event-selector]

  • Note that the problem seems related to the number of different visited tab pages : if I keep 3 jumps on tabs, but I only visit 2 (and not 3) different tab pages, then it is ✅ too :
    [event-selector]
    --(select event | push)--> [event schedule]
    --(switch on tab favorites | ??? (not sure if push or replace)) --> [event favorites]
    --(switch back tab schedule | ??? (not sure if push or replace)) --> [event schedule]
    --(back button clicked | pop) --> [event-selector]

Expected Behavior

Whatever the number of tab switches, a call to :

router.navigate('/event-selector', 'back', 'pop')

should remove tabbed view from the history stack.

Steps to Reproduce

  1. Clone repository : git clone -b router-pop-issue-on-tabs-repro https://github.com/voxxrin/voxxrin3.git && cd voxxrin3/mobile/
  2. Install npm dependencies (with node@18+) : npm ci
  3. Run vite server : npm run dev
  4. Open the app, then click on the favorited conference
  5. This should open a new page with the conference schedule
  6. Switch on tab "Favorites"
  7. Then Switch on tab "Feedbacks"
  8. Hit the back arrow button on the top => you will be stuck on the "Feedbacks" view despite the fact that the URL has changed to /event-selector

You can use this video to help you navigate into the app

Code Reproduction URL

https://github.com/voxxrin/voxxrin3

Ionic Info

Ionic:

   Ionic CLI       : 7.0.1 (/Users/fcamblor/.npm/_npx/40587b9c37309290/node_modules/@ionic/cli)
   Ionic Framework : @ionic/vue 7.0.4

Capacitor:

   Capacitor CLI      : 5.0.0
   @capacitor/android : 5.0.0
   @capacitor/core    : 5.0.0
   @capacitor/ios     : 5.0.0

Utility:

   cordova-res : not installed globally
   native-run  : 1.7.2

System:

   NodeJS : v18.16.0 (/Users/fcamblor/.nvm/versions/node/v18.16.0/bin/node)
   npm    : 9.5.1
   OS     : macOS Monterey

Additional Information

My website navigation is made of following pages :

  • (home page) /event-selector
  • /events/:eventId/* Event tabbed page with following children :
    • /events/:eventId/schedule
    • /events/:eventId/favorites
    • /events/:eventId/feedbacks
    • /events/:eventId/infos

Here is my router config :

const routes: Array<RouteRecordRaw> = [
  { path: '/', redirect: '/event-selector' },
  { path: '/event-selector', component: EventSelectorPage },
  { path: '/events/:eventId', component: () => import('@/views/event/_BaseEventPages.vue'), children: [
    { path: '', redirect: (route) => `/events/${route.params.eventId}/schedule` },
    { path: 'schedule', component: () => import('@/views/event/SchedulePage.vue') },
    { path: 'favorites', component: () => import('@/views/event/FavoritesPage.vue') },
    { path: 'feedbacks', component: () => import('@/views/event/FeedbacksPage.vue') },
    { path: 'infos', component: () => import('@/views/event/InfosPage.vue') },
  ]}
]

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes
})

Navigation from /event-selector to /events/:eventId/* page is made through a push + forward router navigation :

async function selectEvent(eventId: EventId) {
    await fetchConferenceDescriptor(eventId);

    router.push(`/events/${eventId.value}`);
}

On every /events/:eventId/* pages, I have a header component allowing to navigate back to the /event-selector page with pop + back router navigation :

function backToEventsList() {
    unsetCurrentSchedule();

    router.navigate('/event-selector', 'back', 'pop')
}

My tabs are declared normally, using <ion-tab-button> with href navigation links :

<template>
  <ion-page>
    <ion-tabs>
      <ion-router-outlet></ion-router-outlet>
      <ion-tab-bar slot="bottom">
        <ion-tab-button v-for="(tab, index) in tabs" :key="index"
            :tab="tab.id" @click="(ev: Event) => tabClicked(tab, ev)" :href="tab.url">
          <ion-icon aria-hidden="true" :src="selectedTab === tab.id ? tab.selectedIcon : tab.icon"/>
          <ion-label>{{ tab.label }}</ion-label>
        </ion-tab-button>
      </ion-tab-bar>
    </ion-tabs>
  </ion-page>
</template>

<script setup lang="ts">
....
const tabs = [{
  id: 'schedule', url: `/events/${eventId.value.value}/schedule`, label: 'Schedule',
  icon: '/assets/icons/line/calendar-line.svg',
  selectedIcon: '/assets/icons/solid/calendar.svg',
}, {
....
}];
</script>
@ionitron-bot ionitron-bot bot added the triage label May 10, 2023
@liamdebeasi liamdebeasi self-assigned this May 10, 2023
@liamdebeasi
Copy link
Contributor

Thanks for the issue. I am going to close this as a duplicate of #25213.

@liamdebeasi liamdebeasi closed this as not planned Won't fix, can't repro, duplicate, stale May 10, 2023
@liamdebeasi liamdebeasi removed their assignment May 10, 2023
@fcamblor
Copy link
Author

fcamblor commented May 10, 2023

@liamdebeasi I'm not sure if this is completely related (to be honest, it's hard to follow what's going on on #25213 videos as we don't really see where user clicks and what are the URLs involved)

I'd say there are 2 differences :

  • I can't explain why following scenario works if separate tab navigation is not supposed to work properly

Following navigation is ✅ too :
[event-selector]
--(select event | push)--> [event schedule]
--(switch on tab favorites | ??? (not sure if push or replace)) --> [event favorites]
--(back button clicked | pop) --> [event-selector]

  • In my opinion, this is not something normal to get stuck on the tabbed view whilst the url targets the non-tabbed view (/event-selector)

@liamdebeasi
Copy link
Contributor

There are a few issues here. The first is #25213. This is a bug where trying to go back within a tab does not render the correct view due to how the histories for each tab managed internally.


The second issue is the current UI implementation is not really how tabs are supposed to be used. A back button within a tab should always work within the tab itself, and it should never take you out of the tab.

For example, a back button inside /tab1/child should take you to /tab1 (the root Tab 1 page). It should never take you to Tab 2, or some non-tab page. This is covered in https://ionicframework.com/docs/vue/navigation#switching-between-tabs, so it's recommended to treat each tab as its own navigation stack.

If you want a global header that brings users back to the root non-tab page, then the header should be placed in _BaseEventsPages so it exists in the top-level router outlet not the nested tabs router outlet.


The third issue I see in CurrentEventHeader is that when clicking the back button the application tries to push a new instance of /event-selector using a "pop" animation. Instead, you should be going back to the previous instance of /event-selector that users were on using router.go. We unfortunately don't provide a great way of doing this easily, so you'll need to keep track of how far to go manually. Vue Router keeps track of route positions in window.history.state.position. This lets you figure out the delta for how far you need to go.

For example, if the current route position is 14, and the position of the original /event-selector route is 12, then you can do router.go(14 - 12) to go back to the original /event-selector route.

@fcamblor
Copy link
Author

Thanks a lot Liam for your detailed response, that's very valuable !

If you want a global header that brings users back to the root non-tab page, then the header should be placed in _BaseEventsPages so it exists in the top-level router outlet not the nested tabs router outlet.

Putting <current-event-header> in _BaseEventsPages was what I implemented first, but I moved it in tabbed pages few times after as I never succeeded to integrate this component to the global app scrollbar (scrollbar was "starting" after the header, which was undesirable in my case unfortunately :( )

That being said, I was able to confirm that by moving back <current-event-header> in _BaseEventsPages, my stack history navigation "bug" was resolved.


Wow, I just learned that the pop option in navigate(..., ..., 'pop') was only a matter of animation (right ?).
I thought it would have an impact on the way stack history was going to be managed by the router.
Looks like I was wrong, thanks for this precision.

fcamblor added a commit to voxxrin/voxxrin3 that referenced this issue May 11, 2023
…tabs parent page instead of directly from current-event-header component

this fixes bug described here: ionic-team/ionic-framework#27443
@fcamblor
Copy link
Author

fcamblor commented May 11, 2023

FYI, I found a workaround to my problem by :

  • keeping my <current-event-header> component duplicated across my tabbed views (otherwise, I can't sort the scrollbar issue)
  • and by using global window event dispatching triggered from my child component and handled into _BaseEventsPages
    (I didn't succeed to make the event bubble through <ion-router-outlet>)

fcamblor added a commit to voxxrin/voxxrin3 that referenced this issue May 11, 2023
…tabs parent page instead of directly from current-event-header component

this fixes bug described here: ionic-team/ionic-framework#27443
@ionitron-bot
Copy link

ionitron-bot bot commented Jun 10, 2023

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.

@ionitron-bot ionitron-bot bot locked and limited conversation to collaborators Jun 10, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants