0

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
  • I actually do need the slot + a tag here because the component slot this exists within does not get the correct DOM that it expects if you do not write it this way. It turns out I needed to add @click="routerProps.navigate" to the internal a tag. Commented Oct 12, 2023 at 20:35

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

@KaiKai - Thanks I did finally figure this out prior to checking back here, which is that I needed to add @click="routerProps.navigate" to the <a> tag -- I didn't need to wrap it in a closure (I'm not sure why you did when even the docs you linked do not). I'm somewhat surprised I had to do this manually, I would have assumed that v-bind="props.action" would have done this form me but I guess not.
@RickKukiela You can view the implement of <RouterLink>. <RouterLink custom> directly show default slot but <RouterLink :custom="false"> wrapped <a @click="link.navigate" ...>. As for the closure, it's my mistake, edit

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.