Vuejs 3 emit event from child to parent component
Asked Answered
K

2

30

I've recently started working with VueJS, I'm using v3 and seem to be having an issue calling a method on a parent. The emit function in the child doesn't seem to be emitting the event and nothing is getting picked up in the parent.

I've included the parent and child to show how I have it set up

Parent

<template>
  <First/>
  < Child v-bind:sample="sample" @enlarge-text="onEnlargeText"/>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import axios from 'axios';
import First from './First.vue';
import Child from './Child.vue';

export default defineComponent({
  name: 'Container',
  components: {
    First,
    Child,
  },
  methods: {
    onEnlargeText() {
      console.log('enlargeText');
    },
  },
  data: () => ({
    sample: [],
    parentmessage: '',
  }),
  created() {
    axios.get('http://localhost:8080/getData')
      .then((response) => {
        console.log(response);
        this.sample = response.data;
      })
      .catch((error) => {
        console.log(error);
      });
  },
});
</script>

Child

<template>
  <div id="add">
    <form id="signup-form" @submit.prevent="submit">
      <label for="text">Text:</label>
      <input type="text" v-model="text" required>
      <p class="error" >{{ error }}</p>
      <div class="field has-text-right">
        <button type="submit" class="button is-danger">Submit</button>
      </div>
    </form>
    <button v-on:click="tryThis">
      Enlarge text
    </button>
</div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue';
import axios from 'axios';

interface SampleInterface {
  text: string;
  error: string;
}

export default defineComponent({
  name: 'Add',
  data: (): AddInterface => ({
    text: '',
    error: '',
  }),
  methods: {
    tryThis() {
      this.$emit('enlarge-text');
    },
    submit() {
      this.$emit('enlarge-text');
    },
  },
});
</script>

How should this be done? Is there something I've missed?

I was wondering can I still use $emit here?

Keening answered 30/10, 2020 at 9:34 Comment(4)
do you have errors in console?Kempf
@BoussadjraBrahim no errors are appearing in the console unfortunatelyKeening
could you enrich this codesandbox example with your code in order to debug itKempf
I've enriched the example. It now contains a container showing a button. Then when you press the button it should output a logline for the event received in the parent container. Codesandbox: codesandbox.io/s/vue-3-ts-forked-gnlenKeening
K
42

You should add the new emits option containing the emitted event names :

child :

<template>
  <div id="child">
    <button v-on:click="tryThis">Enlarge text</button>
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  name: "Child",
  emits: ["enlargeText"],
  methods: {
    tryThis() {
      console.log("trying");
      this.$emit("enlargeText", "someValue");
    },
  },
});
</script>

or with script setup syntax :

<template>
  <div id="child">
    <button v-on:click="tryThis">Enlarge text</button>
  </div>
</template>

<script lang="ts">

 const emit= defineEmits(["enlargeText"])
 
  function tryThis() {
      console.log("trying");
      emit("enlargeText", "someValue");
    }

</script>

Parent :

<template>
  <div>
    <p>Container</p>
    <Child @enlargeText="onEnlargeText" />
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
import Child from "./Child.vue";

export default defineComponent({
  name: "UrlContainer",
  components: {
    Child,
  },
  methods: {
    onEnlargeText() {
      console.log("enlarging text");
    },
  },
});
</script>

LIVE DEMO

Kempf answered 30/10, 2020 at 13:2 Comment(7)
I've ran this in the demo and I don't see the 'enlarging text' output from the onEnlargeText function. I think this should be output here?Keening
It works with camelCase format please check this codesandbox.io/s/vue-3-ts-forked-3kg1q?file=/src/components/…Kempf
I haven't downvoted, don't worry you've been so helpful! Why does this need to be camelcase? In the docs it says it should be event name casing?Keening
i know that you didn't do that, i think it's a bug i post this answer in which i recommend to use cabeb-case but when i tried that with vue 3 it doesn't workKempf
Fair enough! This works with canal case, I'm going to mark as complete :)Keening
I will post an issue in vue-next repoKempf
this the issue that i postedKempf
S
2

Or could use v-model and update event:

// ChildComponent.vue
<template>
  <div>
    <input type="button" @click="increment" value="Click" />
    childCounter: {{ childCounter }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      childCounter:0
    }
  },
  methods: {
    increment() {
      // emit custom update event to update the parent value
      this.$emit('update:childCounter', ++this.childCounter);
    }
  }
}
</script>
// ParentComponent.vue
<template>
  <div>
    <!-- basically means:
      <Child :childCounter="parentCounter" 
             @update:childCounter="(childCounter) => parentCounter = childCounter"
    />
    -->
    <Child v-model:childCounter="parentCounter"></Child>
    parentCounter: {{ parentCounter }}<br/>
  </div>
</template>

<script>
import Child from './ChildComponent.vue'

export default {
  components: {
    Child
  },
  data() {
    return {
      parentCounter: 0
    }
  },
}
</script>
Stomachic answered 11/4, 2023 at 11:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.