Vue Router <router-link> with custom attribute + slot template not routing on frontend (SPA)

257 views Asked by At

I'm not sure any of this really matters, but I am using Nuxt3/Vue3 with Primefaces/PrimeVue UI framework, and specifically struggling with the <Menubar> #item template slot.

The gist of the situation is that in the template code that renders the menu buttons, I have this code:

<router-link v-slot="routerProps" :to="item.route" custom>
    <a :href="routerProps.href" v-bind="props.action">
        <span v-bind="props.icon" />
        <span v-bind="props.label">{{ label }}</span>
    </a>
</router-link>

The above results in everything looking perfect, but when the menu buttons are clicked, the browser treats it like an external link, sends a GET request for the specified route, then rebuilds the page from scratch which causes the entire application to be "rebooted". This is obviously not what I want in my SPA app.

I'm not using any SSR stuff (if it matters).

I have tried using <NuxtLink> instead of <router-link> and get the same behavior.

I have tried removing the <a> tag from the internal HTML (leaving the <span> tags) and this "works" as far as the the routing is concerned, but then the <Menubar> element is not rendered correctly and looks broken.

Removing the custom attribute and inner HTML of the nuxt/router link element also "works" but does not look correct on the render.

The only way I have been able to get this to work from both a visual and routing perspective was to replace the inner <a> tag with either a <router-link> or <NuxtLink> element, however this causes some crazy vuejs core errors if this componenent is ever unloaded for any reason during the beforeUnmount lifecycle hook. So this is obviously not the correct solution.

Am I missing something? Or is this an issue that needs to be resolved by the PrimeVue component author?

EDIT: Per @KaiKai's answer and the vue docs, the missing key was adding @click="routerProps.navigate" to the <a> tag.

Final working code:

<router-link v-slot="routerProps" :to="item.route" custom>
    <a :href="routerProps.href" v-bind="props.action" @click="routerProps.navigate">
        <span v-bind="props.icon" />
        <span v-bind="props.label">{{ label }}</span>
    </a>
</router-link>
1

There are 1 answers

2
Zihan Hu On BEST ANSWER

You can use slot props of <RouterLink>. (docs)

<router-link v-slot="routerProps" :to="item.route" custom>
  <a
    :href="routerProps.href"
    v-bind="props.action"
    @click="routerProps.navigate"
  >
    <span v-bind="props.icon" />
    <span v-bind="props.label">{{ label }}</span>
  </a>
</router-link>

If you're using Nuxt, replacing router-link with nuxt-link is better.