skip to Main Content

I created a Header component that has a IonMenu component in it for a reusable header across pages. The menu is tied to the IonRouterOutlet as the docs suggest but its giving me an issue when navigating between pages. Once I navigate between pages, it breaks the click event on the menu button and I can never get the menu to open again unless I do a refresh on the page(F5), what’s the issue here?

Once on the homepage(/dashboard) the menu works fine. If I open the menu and then click the Profile link I move to that page and the menu again works fine. Once I click the back arrow to move back to the homepage, the menu no longer works.

Code Sandbox example here

App.vue

<template>
  <ion-app>
    <ion-router-outlet id="main-content" />
  </ion-app>
</template>

<script setup lang="ts">
import { IonApp, IonRouterOutlet } from "@ionic/vue";
</script>

Header.vue

<template>
  <ion-header>
    <ion-toolbar color="primary">
      <ion-buttons slot="start">
        <ion-back-button defaultHref="/" />
      </ion-buttons>
      <ion-title>Title</ion-title>
      <ion-buttons slot="end">
        <slot>
          <ion-menu-button />
        </slot>
      </ion-buttons>
    </ion-toolbar>
  </ion-header>
  <HeaderMenu color="primary" />
</template>

<script setup lang="ts">
import {
  IonHeader,
  IonTitle,
  IonToolbar,
  IonButtons,
  IonMenuButton,
  IonBackButton,
  IonButton,
} from "@ionic/vue";
import HeaderMenu from "./HeaderMenu.vue";
</script>

HeaderMenu.vue

<template>
  <IonMenu side="end" content-id="main-content">
    <IonHeader>
      <IonToolbar color="primary"></IonToolbar>
    </IonHeader>
    <IonContent>
      <IonItemGroup>
        <IonList class="ion-no-padding">
          <IonMenuToggle>
            <IonItem class="ion-text-center">
              <IonButton
                expand="full"
                fill="clear"
                size="small"
                @click="navigate('dashboard')"
              >
                <span>Dashboard</span>
              </IonButton>
            </IonItem>
            <IonItem class="ion-text-center">
              <IonButton
                expand="full"
                fill="clear"
                size="small"
                @click="navigate('profile')"
              >
                <span>Profile</span>
              </IonButton>
            </IonItem>
          </IonMenuToggle>
        </IonList>
      </IonItemGroup>
    </IonContent>
  </IonMenu>
</template>

<script setup lang="ts">
import {
  IonHeader,
  IonToolbar,
  IonMenu,
  IonMenuToggle,
  IonContent,
  IonButton,
  IonList,
  IonItem,
  IonItemGroup,
  IonIcon,
} from "@ionic/vue";
import router from "../router";

const navigate = (routeName: string) => {
  router.push({ name: routeName });
};
</script>

<style>
/* This fixes the issue with the menu not being clickable */
.menu-content-open {
  pointer-events: unset !important;
}
</style>

2

Answers


  1. This is a tricky bug in Ionic. It’s been around for a long time and they still haven’t solved it. See this GitHub issue for more details.

    However, they don’t provide a resolution that works for everyone, and no solution for Vue. I’ve had some issues with IonMenu as well, so I figured I’d take a crack at the problem.

    I modified your code, and it works in my environment. The gist of it is that the menu remains disabled after switching routes, and it is complicated by animations. I added a computed disabled and onBeforeRouteLeave handlers. I only had success with both in play. This required menus to have a menu-id, and instead of making a bunch of props, I just used provide(). My changes are below.

    Dashboard.vue

    <template>
      <IonPage>
        <Header />
    
        <IonContent :fullscreen="true">
          <span>Dashboard</span>
        </IonContent>
      </IonPage>
    </template>
    
    <script setup lang="ts">
    import {IonContent, IonPage, menuController} from "@ionic/vue";
    import Header from "../components/Header.vue";
    import {onBeforeRouteLeave} from "vue-router";
    import {provide} from "vue";
    
    const menuId = "dashboard-menu"
    provide("menu-id", menuId)
    provide("route-name", "dashboard")
    
    onBeforeRouteLeave(async () => {
      await menuController.close(menuId)
      await menuController.enable(true, menuId)
    })
    
    </script>
    

    Profile.vue

    <template>
      <IonPage>
        <Header />
        <IonContent :fullscreen="true">
          <span>Profile Page</span>
        </IonContent>
      </IonPage>
    </template>
    
    <script setup lang="ts">
    import {IonContent, IonPage, menuController} from "@ionic/vue";
    import Header from "../components/Header.vue";
    import {onBeforeRouteLeave} from "vue-router";
    import {provide} from "vue";
    
    const menuId = "profile-menu"
    provide("menu-id", menuId)
    provide("route-name", "profile")
    
    onBeforeRouteLeave(async () => {
      await menuController.close(menuId)
      await menuController.enable(true, menuId)
    })
    
    </script>
    
    <style>
    ion-modal {
      --height: auto;
    }
    </style>
    

    HeaderMenu.vue

    <template>
      <IonMenu side="end" :menu-id="menuId" content-id="main-content" :disabled="disabled">
        <IonHeader>
          <IonToolbar color="primary"></IonToolbar>
        </IonHeader>
        <IonContent>
          <IonItemGroup>
            <IonList class="ion-no-padding">
              <IonMenuToggle>
                <IonItem class="ion-text-center">
                  <IonButton
                    expand="full"
                    fill="clear"
                    size="small"
                    @click="navigate('dashboard')"
                  >
                    <span>Dashboard</span>
                  </IonButton>
                </IonItem>
                <IonItem class="ion-text-center">
                  <IonButton
                    expand="full"
                    fill="clear"
                    size="small"
                    @click="navigate('profile')"
                  >
                    <span>Profile</span>
                  </IonButton>
                </IonItem>
              </IonMenuToggle>
            </IonList>
          </IonItemGroup>
        </IonContent>
      </IonMenu>
    </template>
    
    <script setup lang="ts">
    import {
      IonHeader,
      IonToolbar,
      IonMenu,
      IonMenuToggle,
      IonContent,
      IonButton,
      IonList,
      IonItem,
      IonItemGroup,
    } from "@ionic/vue";
    import {computed, inject} from "vue";
    import {useRouter} from "vue-router";
    
    const routeName = inject("route-name")
    const menuId: string = inject("menu-id")!
    const router = useRouter()
    
    const disabled = computed(() => {
      return router.currentRoute.value.name !== routeName
    })
    
    const navigate = (routeName: string) => {
      router.push({ name: routeName });
    };
    </script>
    
    <style>
    /* This fixes the issue with the menu not being clickable */
    .menu-content-open {
      pointer-events: unset !important;
    }
    </style>
    
    Login or Signup to reply.
  2. I have see your code in HeaderMenu.vue page in IonToolbar component in set
    your url and in defaultHref also set daynamic and static url(router).

    ex:-

    <ion-buttons slot="start">
         <ion-back-button defaultHref="/" />
    </ion-buttons>
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search