70

I'm attempting to add a custom handler InlineButtonClickHandler to a <router-link> component's click event, so that I can emit a custom appSidebarInlineButtonClick event.

But, my code isn't working. What am I doing wrong?

<template>
   <router-link :to="to" @click="InlineButtonClickHandler">
     {{ name }}
   </router-link>
</template>

<script type="text/babel">
export default {
  props: {
    to: { type: Object, required: true },
    name: { type: String, required: true }
  },
  methods: {
    InlineButtonClickHandler(event) {
      this.$emit('appSidebarInlineButtonClick');
    }
  }
} 
</script>
1
  • <a @click="$router.push(to).then(InlineButtonClickHandler)">{{name}}</a> for vue 3 Commented Sep 27, 2023 at 16:12

4 Answers 4

158

You need to add the .native modifier:

<router-link
    :to="to"
    @click.native="InlineButtonClickHandler"
>
    {{name}}
</router-link>

This will listen to the native click event of the root element of the router-link component.

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

4 Comments

v-on:click.native is deprecated now, from what I read
Given that "@click.native" is deprecated in Vue.js 3, an alternate option is to use a button styled as a link and in its @click method call this.$router.push({ path: 'to' });
@click.native or v-on:click.native is now deprecated in new versions of VueJS (>=3), use @click.prevent instead.
For Vue3: Until/unless there's an official way handled by VueRouter, this may be an alternative solution: github.com/vuejs/router/issues/846#issuecomment-808150258
11
<router-link:to="to">
    <span @click="InlineButtonClickHandler">{{name}}</span>
</router-link>

Maybe you can try this.

2 Comments

This will not be accessible since keyboard users could never activate that @click event
this will create inconsistencies. If, for some reason, you need a padding/margin in between the router link and span you will have zones of the link where you get routed but the click event is not triggered.
4

With vue 3 and vue router 4 the @event and tag prop are removed according to this and instead of that you could use v-slot:

const Home = {
  template: '<div>Home</div>'
}
const About = {
  template: '<div>About</div>'
}
let routes = [{
  path: '/',
  component: Home
}, {
  path: '/about',
  component: About
}, ]

const router = VueRouter.createRouter({
  history: VueRouter.createWebHashHistory(),
  routes,
})


const app = Vue.createApp({
  methods: {
    test() {
      console.log("test")
    }
  }
})

app.use(router)

app.mount('#app')
<script src="https://unpkg.com/vue@3"></script>
<script src="https://unpkg.com/vue-router@4"></script>

<div id="app">
  <h1>Hello App!</h1>
  <p>

    <router-link to="/" v-slot="{navigate}">
      <span @click="test" role="link">Go to Home</span>
    </router-link>
    <br/>
    <router-link to="/about">Go to About</router-link>
  </p>

  <router-view></router-view>
</div>

Comments

1

What I ended up doing is creating a wrapper component for the router link which emits the native click event as a regular click and then use that component instead:

<template>
  <router-link v-bind="$attrs" v-on="$listeners" @click.native="onClick">
    <slot />
  </router-link>
</template>

<script>
export default {
  name: 'RouterLinkWithClickEvent',
  methods: {
    onClick(...args) {
      this.$emit('click', ...args);
    }
  }
};
</script>

Comments

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.