Juckix
Juckix

Reputation: 35

Vue 3, call $emit on variable change

So I'm trying to build a component in Vue 3 that acts as a form, and in order for the data to be processed by the parent I want it to emit an object with all the inputs on change. The issue I'm having is that I don't seem to be able to call $emit from within watch() (probably because of the context, but I also don't see why the component-wide context isn't passed by default, and it doesn't accept this). I also cannot call any method because of the same reason.

I do see some people using the watch: {} syntax but as I understand it that is deprecated and it doesn't make a whole lot of sense to me either.

Here's a minimal example of what I'm trying to accomplish. Whenever the input date is changed, I want the component to emit a custom event.

<template>
  <input
    v-model="date"
    name="dateInput"
    type="date"
  >
</template>

<script>
import { watch, ref } from "vue";

    export default {
        name: 'Demo',
        props: {
        },
        emits: ["date-updated"],
        setup() {
          const date = ref("")

          watch([date], (newVal) => {
            // $emit is undefined
            console.log(newVal);
            $emit("date-updated", {newVal})
            // watchHandler is undefined
            watchHandler(newVal)
          })

          return {
            date
          }
        },
        data() {
            return {
            }
        },
        mounted() {
        },
        methods: {
          watchHandler(newVal) {
            console.log(newVal);
            $emit("date-updated", {newVal})
          }
        },
    }
</script>

Upvotes: 2

Views: 17266

Answers (2)

Y B
Y B

Reputation: 11

How should I do this in setup syntactic sugar

const emits = defineEmits(['confirmCallBack', 'cancelCallBack', 'closeCallBack', 'openCallBack', 'update:modelValue'])
const dialogForm = ref<CommonForm >({})

watch(dialogForm.value, (val) => {
  consola.start('数据更新')
  emits('update:modelValue', val)
})

Upvotes: 1

Boussadjra Brahim
Boussadjra Brahim

Reputation: 1

Don't mix between option and composition api in order to keep the component consistent, the emit function is available in the context parameter of the setup hook::

<template>
  <input
    v-model="date"
    name="dateInput"
    type="date"
  >
</template>

<script>
import { watch, ref } from "vue";
export default {
        name: 'Demo',
        props: {},
        emits: ["date-updated"],
        setup(props,context) {// or setup(props,{emit}) then use emit directly
          const date = ref("")

          watch(date, (newVal) => {
            context.emit("date-updated", {newVal}) 
          })

          return {
            date
          }
        },  
    }
</script>

if you want to add the method watchHandler you could define it a plain js function like :

...
 watch(date, (newVal) => {
            context.emit("date-updated", {newVal}) 
          })

  function watchHandler(newVal) {
            console.log(newVal);
           context.emit("date-updated", {newVal})
          }
...

Upvotes: 4

Related Questions