Reputation: 17160
I have the following component:
<SomeModal :is-modal-active="isAddingThing" @close="isAddingThing = false" />
Inside that component looks like this:
<script setup>
import { defineProps } from 'vue'
const props = defineProps({
isModalActive: Boolean,
})
const handleClose = () => {
emit('close') // doesn't work
}
</script>
<template>
<V-Modal @close="handleClose">
...
</V-Modal>
</template>
How do I emit to parent?
Upvotes: 48
Views: 77070
Reputation: 35714
Vue 3.2
and newerThe useContext
and getCurrentInstance
APIs were deprecated and are no longer exposed to the Vue 3 API. Instead of that, you should use the defineEmits
at the root level on the setup script.
<template>
<button @click="action('🎉')"></button>
</template>
<script setup>
const emit = defineEmits(['close', 'unClose'])
const action = () => emit('close', val);
</script>
and for typescript the definition would be:
const emit = defineEmits<{
(e: 'close', val: string): void
(e: 'unClose', id: number): void
}>()
Vue 3.2
$emit
from the templateuseContext
provides the emit function for use in setup functiondefineEmits
adds the list of emits to the component (equivalent to emits:
definition of component) but doesn't help with the emituseContext
and defineEmits
are deprecated as of Vue 3.2, use getCurrentInstance
and defineEmits
useContext
<template>
<button @click="action('🎉')"></button>
<!-- emit is defined through useContext -->
<button @click="emit('action1','🥑')">1</button>
<!-- $emit here doesn't need to be defined -->
<button @click="$emit('action2','🦄')">2</button>
</template>
<script setup>
import { defineProps, useContext } from 'vue'
const { emit } = useContext()
const action = (id) => emit('action', id);
</script>
Note that vetur extension might tell you that it's deprecated and that you should use useSlots
and useAttrs
instead. If you want to use emit
from the script, those, obviously, won't help with that.
getCurrentInstance
import { defineProps, getCurrentInstance} from 'vue'
const { emit } = getCurrentInstance()
In addition to running an emit, vue3 allows (recommends🤷♂️) that the emits are defined, so the component parent might know what events a component might emit. To do that using the <script setup>
form, you can use defineEmit
<script setup>
import { defineEmit } from 'vue'
const emit = defineEmit(['action'])
const action = (id) => emit('action', id);
</script>
This will allow sending action
emit event, but if you emit a doit
although it will still emit, you'll get a warning in the console
[Vue warn]: Component emitted event "doit" but it is neither declared in the emits option nor as an "onDoit" prop.
Upvotes: 34
Reputation: 952
With Vue version 3.2, if you want to emit an event from inside <script setup>
, then all you have to do is define your emits with the defineEmits()
method that is automatically available inside <script setup>
(you don't have to import it), then you can emit the event by calling emit('myEventName', myParams)
. Here's some sample code...
<script setup>
const emit = defineEmits(['eventA', 'eventB'])
function btnClick(params) {
emit('eventA')
emit('eventB', params)
}
</script>
Upvotes: 66