1
votes

Currently I have something like the following code inside my <script>:

render(createElement) {
 return createElement("form", 
   {ref: "formEl" ,
     on: {submit: this.handleSubmit}
   }, 
   [ <insert create form inputs here> ]);
}

handleSubmit(e) {
 e.preventDefault();
 //Other stuff that also rely on using e
}

If I place a submit button inside the form handleSubmit works and runs perfectly. But if I were to do this.$refs.formEl.submit() HandleSubmit does not run.

I have tried a solution posted in: VueJs 2 - preventDefault() on $refs.form.submit()

By adding a event listening like so: this.$refs.form.addEventListener("submit", this.handleSubmit);

Sadly this did not work.

Edit (After Comments): To elaborate on "not work": what I found to happen is when pressing a submit button contained inside the <form> tags HandleSubmit() is actually ran twice (im assuming dude to adding a listener twice) And I added some console.log() to handlesubmit and found nothing on console.

The component is made in Typescript with classes and I am pretty certain it is in the equivalent to the methods section of the component for typescript: (inside export default class ClassName extends Vue {})

What I find is that if I attach a button outside the <form> tag that triggers the submit() method on the reference the default action of updating the URL with the form contents is performed.

1
How exactly did it not work, any error in the console? You also mentioned "it does not run", can you confirm if this handleSubmit function is actually inside the methods section of the component?Yom T.
Hi @YomS. I've updated the post to address your comment, as for errors there are none. Thanks for taking a look!Jahson
Would setting the ref attribute on the form component manually make any difference for you? Sounds like you wanted to programmatically invoke the form submission outside of the component.Yom T.

1 Answers

0
votes

This seems to be working fine (without a ref). No doubled submission issue for me.

The component is made in Typescript with classes and I am pretty certain it is in the equivalent to the methods section of the component for typescript: (inside export default class ClassName extends Vue {})

Yes, you're right.

But here's a quick demo in Javascript. (The Typescript equivalent should be close enough).

new Vue({
  el: '#app',

  components: {
    TheForm: {
      props: {
        prevent: Boolean
      },
      
      render(createElement) {
        return createElement("form", {
          //ref: "formEl",
          on: {
            submit: this.handleSubmit
          }
        }, this.$slots.default);
      },

      methods: {
        handleSubmit(e) {
          if (this.prevent) {
            e.preventDefault();
          }
          //Other stuff that also rely on using e
        }
      }
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>

<div id="app">
  <p>Clicking on this should do nothing, since the default page-redirecting behavior is prevented.</p>
  <the-form action="/should-be-prevented" prevent>
    <input type="submit" value='Do "prevented" submission' />
  </the-form>

  <p>This should work like normal submit buttons would. And once submitted, the whole screen should go blank (showing that the page has been redirected somewhere else).</p>
  <the-form action="/should-redirect">
    <input type="submit" value='Do "normal" submission' />
  </the-form>
</div>

Form submission with ref:

new Vue({
  el: '#app',
  
  components: {
    TheForm: {
      props: {
        prevent: Boolean
      },
      
      render(createElement) {
        return createElement('form', {
          on: {
            submit: this.handleSubmit
          }
        }, this.$slots.default);
      },

      methods: {
        handleSubmit(e) {
          if (this.prevent) {
            e.preventDefault();
          }
          else {
            this.$el.submit(e);
          }

          //Other stuff that also rely on using e
        }
      }
    }
  }
})
form {
  border: 2px dotted lightgray;
  margin: 1rem auto;
  padding: 1rem;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>

<div id="app">
  <the-form ref="form1" action="/should-be-prevented" prevent>
    This form should stay, since the default page-redirecting behavior is prevented.
  </the-form>

  <the-form ref="form2" action="/should-redirect">
    This should work like normal forms would. And once submitted, the whole screen should go blank (showing that the page has been redirected somewhere else).
  </the-form>

  <hr />
  <p>Note that these buttons are <strong>outside</strong> of the respective forms, to demonstrate programmatic form-submission trigger. </p>
  <input @click="$refs.form1.handleSubmit($event)" value='Do "prevented" submission' type="button" />
  <input @click="$refs.form2.handleSubmit($event)" value='Do "normal" submission' type="button" />
</div>