Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Form component in Vue fires submit event twice

I'm using the latest version of Vue 3, with no other vendors.

It may be a bug, or it is an expected behaviour, but I lost a couple of hours finding why my form component was firing the submit event twice.

It fact, if you listen to @submit on your form, and then $emit('submit') so you can listen to this event on the parent component, the event will be fired twice.

More than words, here is a pen to show this: https://codepen.io/rekam/pen/dyeqxyy

const { createApp } = Vue

const TestForm = {
  template: `
    <form @submit.prevent.stop="onSubmit">
      <input type="text" />
      <input type="submit" value="in component" />
    </form>
  `,
  props: {
    eventName: { type: String }
  },
  methods: {
    onSubmit() {
      this.$emit(this.eventName)
    }
  }
}

createApp({
  template: `
    <div>
      <TestForm event-name="submit" @submit="() => onSubmit('with event name [submit]')" />
      <TestForm event-name="other" @other="() => onSubmit('with event name [other]')" />
      <blockquote>
        <p v-for="(log, i) in logs" :key="i">{{ log }}</p>
      </blockquote>
      <input type="button" value="clear" @click="logs = []" />
    </div>
  `,
  components: { TestForm },
  data: () => ({
    logs: []
  }),
  methods: {
    onSubmit(msg) {
      console.log(msg)
      this.logs.push(msg)
    }
  }
}).mount('#app')

I can live with that, I just need to give a specific name to my own submit event. My question is: why is this happening and is it expected?

EDIT

I just found that wrapping the form tag in a div get rid of the second submit event. To have the submit event fired twice, you need:

  1. your form beign the top level dom element in your component
  2. emit an event named "submit"
like image 983
rekam Avatar asked Jan 30 '26 17:01

rekam


2 Answers

You dont need to add the event @submit.prevent.stop="onSubmit" in you're child component because it will be inherited from the parent component';

template: `
    <form>
      <input type="text" />
      <input type="submit" value="in component" />
    </form>
  `,

template: `
    <div>
      <TestForm event-name="submit" @submit.prevent="() => onSubmit('with event name [submit]')" />
      <TestForm event-name="other" @submit.prevent="() => onSubmit('with event name [other]')" />
      <blockquote>
        <p v-for="(log, i) in logs" :key="i">{{ log }}</p>
      </blockquote>
      <input type="button" value="clear" @click="logs = []" />
    </div>
  `,

https://codepen.io/keyXpert/pen/dyegYQB

like image 105
Taha Azzabi Avatar answered Feb 01 '26 05:02

Taha Azzabi


you call submit twice with an eventlistener you created from emit and another from @submit you added to your form tag. you should use one of them to submit your form.

like image 34
Negin Khademian Avatar answered Feb 01 '26 07:02

Negin Khademian



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!