Vue v-on:click does not work on component
I’m trying to use the on click directive inside a component but it does not seem to work. When I click the component nothings happens when I should get a ‘test clicked’ in the console. I don’t see any errors in the console, so I don’t know what am I doing wrong.
index.html
App.vue
Test.vue (the component)
Solutions/Answers:
Solution 1:
If you want to listen to a native event on the root element of a component, you have to use the .native modifier for v-on
, like following:
<template>
<div id="app">
<test v-on:click.native="testFunction"></test>
</div>
</template>
or in shorthand, as suggested in comment, you can as well do:
<template>
<div id="app">
<test @click.native="testFunction"></test>
</div>
</template>
Solution 2:
I think the $emit
function works better for what I think you’re asking for. It keeps your component separated from the Vue instance so that it is reusable in many contexts.
<template>
<div id="app">
<test @click="$emit('test-click')></test>
</div>
</template>
Use it in HTML
<test @test-click="testFunction">
Solution 3:
It’s the @Neps’ answer but with details.
Note: @Saurabh’s answer is more suitable if you don’t want to modify your component or don’t have access to it.
Why can’t @click just work?
Components are complicated. One component can be a small fancy button wrapper, and another one can be an entire table with bunch of logic inside. Vue doesn’t know what exactly you expect when bind v-model
or use v-on
so all of that should be processed by component’s creator.
How to handle click event
According to Vue docs, $emit
passes events to parent. Example from docs:
Main file
<blog-post
@enlarge-text="onEnlargeText"
/>
Component
<button @click="$emit('enlarge-text')">
Enlarge text
</button>
(@
is the v-on
shorthand)
Component handles native click
event and emits parent’s @enlarge-text="..."
enlarge-text
can be replaced with click
to make it look like we’re handling a native click event:
<blog-post
@click="onEnlargeText"
></blog-post>
<button @click="$emit('click')">
Enlarge text
</button>
But that’s not all. $emit
allows to pass a specific value with an event. In the case of native click
, the value is MouseEvent (JS event that has nothing to do with Vue).
Vue stores that event in a $event
variable. So, it’d the best to emit $event
with an event to create the impression of native event usage:
<button v-on:click="$emit('click', $event)">
Enlarge text
</button>
Solution 4:
A bit verbose but this is how I do it:
@click="$emit('click', $event)"
Solution 5:
Native events of components aren’t directly accessible from parent elements. Instead you should try v-on:click.native="testFunction"
, or you can emit an event from Test
component as well. Like v-on:click="$emit('click')"
.