Netlify Forms with Vue @submit.prevent="handleSubmit"

Hi all,

I am trying to set up an email newsletter form. I want to update the DOM (success message), without a page reload. At the same time, on the backend, a POST request is issued to add this email to my EmailOctopus list (via their API).

My site is built with Gridsome (Vue Static Builder). To prevent redirect to success page I add @submit.prevent attribute to my form:

<form
   name="add-subscriber"
   id="myForm"
   method="post"
   data-netlify="true"
   data-netlify-honeypot="bot-field"
   @submit.prevent="handleFormSubmit">
            <input type="hidden" name="form-name" value="add-subscriber" />
            <input type="email" v-model="userEmail" name="user_email" required="" id="id_user_email">
            <button type="submit" name="button">Subscribe</button>
          </form>

This is how my handleFormSubmit function currently looks like:

handleFormSubmit() {
            document.getElementById("myForm").innerHTML = `
                <div>
                  Almost there! Check your inbox for a confirmation e-mail.  
               </div>`

Now the dom gets updated with a success message, but the form is not actually submitted. Clearly I need to add something else to my function.

Previously I had a POST request with a “/” URL, but I kept getting a Cannot POST / error:

        handleFormSubmit() {
            document.getElementById("myForm").innerHTML = `
                <div>
                  Almost there! Check your inbox for a confirmation e-mail.  
               </div>`

            await axios.post('/', {
                data: {
                    "user_email": this.userEmail,
                    "apiKey": apiKey
                }
            })
            .then(data => console.log(data))
            .catch(error => console.log(error))
        }

My function is called submission-created.js, so it can be launched only when the form submission is registered with Netlify.

My site is currently located at https://rk-gridsome-pw.netlify.com/

Sorry for the long message. I hope this is clear. If further details are needed please let me know. Thanks a ton in advance. I really appreciate everyone’s help!

Best,
Rasul

P.S. I have tried to use Netlify Tutorial and run into a couple of issues described here in a stackoverflow post

Hey @rasulkireev,
Thanks for sharing all the links and code about your what your setup is and what you’ve tried so far. I took a look at your site and see that you have recently received some form submissions:

So is the problem that the submissions aren’t collecting all the data you want? If that’s the issue, based on your StackOverflow post, there might be a problem with how you’re sending data to Netlify, your data encoding function (I don’t see one in the code you sent), etc. Here’s some sample code that may help you debug:

and a more in-depth post about the pieces you need for a form.

Or is that part working correctly and the problem is that EmailOctopus is not receiving the form data after it’s been submitted to Netlify? If it’s the latter, that would suggest an issue with the submission-created function. This tutorial has a good walkthrough with submission-created code:

Let us know how you go with this and if we can help further!

Thank you so much for your response!

I do apologize. I was able to find the answer yesterday. Here is what works for me.

<template>
          <form
          name="add-subscriber"
          id="myForm"
          method="post"
          data-netlify="true"
          data-netlify-honeypot="bot-field"
          enctype="application/x-www-form-urlencoded"
          @submit.prevent="handleFormSubmit">
            <input type="hidden" name="form-name" value="add-subscriber" />
            <input type="email" name="userEmail" v-model="formData.userEmail">
            <button type="submit" name="button">Subscribe</button>
          </form>
 </template>

<script>
import axios from "axios";

export default {
    data() {
        return {
            formData: {
                userEmail: null,
            },
        }
    },
    
    methods: {
        encode(data) {  
            const formData = new FormData();
            
            for (const key of Object.keys(data)) {
                formData.append(key, data[key]);
            }
            
            return formData;
        },

        handleFormSubmit(e) {
            const axiosConfig = {
                header: { "Content-Type": "application/x-www-form-urlencoded" }
            };

            axios.post(
                location.href, 
                this.encode({
                    'form-name': e.target.getAttribute("name"),
                    ...this.formData,
                }),
                axiosConfig
            )
            .then(data => console.log(data))
            .catch(error => console.log(error))
            .then(document.getElementById("myForm").innerHTML = `
            <div>
                Thank you! I received your submission.
            </div>
            `)
        }
    }
}
</script>

Specifically declaring the userEmail helped, as well as correct encoding.

1 Like

awesome! so glad you found a solution, and thanks for posting it. That will definitely help other people.

Hi, I’m running into a similar issue today. I’m using Fetch instead of Axios. I’m using POST, a FormData object for the body, and I keep getting 404 errors when I post. My source is as follows:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Special Contact Form</title>
</head>
<body>
	<h2>Contact Form</h2>

	<form method="post" name="Contact Form 3" action="/thankyou.html" id="myForm"
	@submit.prevent="sendForm" ref="formTag" data-netlify="true">
	<p>
		<label for="name">Name:</label>
		<input type="text" name="name" id="name" v-model="name">
	</p>
	<p>
		<label for="email">Email:</label>
		<input type="email" name="email" id="email" v-model="email">
	</p>
	<p>
		<label for="comments">Comments:</label><br/>
		<textarea name="comments" id="comments" v-model="comments"></textarea>
	</p>
	<p>
		<input type="submit">
	</p>
	</form>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
	el:'#myForm',
	data:{
		name:'',
		email:'',
		comments:''
	},
	methods:{
		async sendForm() {
			let target = this.$refs.formTag.action;
			let name = this.$refs.formTag.getAttribute('name');

			let fd = new FormData();
			fd.append('name', this.name);
			fd.append('email', this.email);
			fd.append('comments', this.comments);
			fd.append('form-name', name);

			let resp = await fetch(target, {
				method:'POST',
				headers: { 
					'Content-Type': 'application/x-www-form-urlencoded' 
				},
				body:fd
			});
//			let data = await resp.json();
//			console.log(data);
		}
	}
});

</script>

</body>
</html>

Any idea why this doesn’t work?

An update - I realized I wasn’t properly encoding my form. On a whim I changed body to a hard coded value:

name=ray&form-name=Contact+Form

This seemed to work! But then I tried to make it dynamic:

encode(data) {
	// Credit - Brian Rinaldi at https://www.stackbit.com/blog/complete-guide-netlify-forms/
 	return Object.keys(data)
	.map(key => encodeURIComponent(key) + "=" + encodeURIComponent(data[key]))
	.join("&");
},
async sendForm() {
	let target = this.$refs.formTag.action;
	let name = this.$refs.formTag.getAttribute('name');

	let fd = {
		'name':this.name,
		'email':this.email,
		'comments':this.comments,
		'form-name':name
	};
			
	let encodedForm = this.encode(fd);
	console.log(encodedForm);
	let resp = await fetch(target, {
		method:'POST',
		headers: { 
			'Content-Type': 'application/x-www-form-urlencoded' 
		},
		body:encodedForm
	});

//			let data = await resp.json();
//			console.log(data);
}

And it failed. I couldn’t understand why my hard coded string worked and the dynamic one did not. Then I noticed something. My hard coded test was using a form name of “Contact Form.” I had a previous form on my Netlify site with that name. When I changed my form name to match, it worked.

So question - why can’t I send an Ajax submission to a form with a name that is “new” to Netlify?

Ok, so I built a new form that didn’t use Ajax. I named it “My Contact Form”. I submitted it. On my Ajax form, I used that name, and it worked. So it sounds like you can’t use an Ajax form until you submit at least once with a regular form. That’s a bug, right?

Hey @cfjedimaster,
Glad to hear you sorted out your Vue form! To make sure I understand, the next issue you raised is not about Vue, but about submitting a vanilla Javascript form using fetch. Is that right? Let us know and we’ll dig in.

Correct - it isn’t a Vue issue, but an “Ajax submit on Netlify” issue. I spoke with Brian Rinaldi and he mentioned he saw this as well.

To test, post with forn name equal to Something. It will fail. Build a simple form that just does a regular post and uses the same name. Now the fancy Ajax one will work.

Hi, @cfjedimaster, this sounds a bit like the “HTML form must exist” requirement mentioned here. Quoting:

If you’re using a pure javascript form instead, this additional step is required:

  • You still need to include an HTML form that meets the criteria above, including all the inputs with the same names as the javascript form. This is required because we parse HTML to find forms during your deploy - but we don’t try to parse javascript files. This means if you are using React, Vue, etc. which create HTML elements using Javascript during the render, you’ll still need to include an actual HTML file that includes all of the form details in it, including all possible inputs that you want to use. For a working example using React that you can generalize to other frameworks from, check out this blog post .

It sounds like the requirement above causing the behavior mentioned here?

I ask because it sounds like this is the issue:

  • javascript form doesn’t work
  • HTML form is created
  • javascript starts working

If this is the issue, that is because the HTML form is required for all forms. If I’ve misunderstood the issue, please let us know.

Close, but I am using an HTML form. Here it is:

This did not work until I built:

This is the same form but with no Ajax. As soon as I submitted that one the Ajax one worked, but again, you can see the ‘regular’ form in form3.html as well, it just uses Ajax to submit it.

Hey @cfjedimaster,
Since this is not about Vue, but about submitting a form using fetch, I don’t think it’s useful to test with Vue as you’re doing in the first example. This example works for me on first submit, without sending a non-fetch form first:



<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Special Contact Form</title>
  </head>
  <body>
    <h2>Contact Form</h2>
    <form method="post" name="Contact Form" id="myForm" data-netlify="true">
      <p>
        <label for="name">Name:</label>
        <input type="text" name="name" id="name">
      </p>
      <p>
        <label for="email">Email:</label>
        <input type="email" name="email" id="email">
      </p>
      <p>
        <label for="comments">Comments:</label><br/>
        <textarea name="comments" id="comments"></textarea>
      </p>
      <p>
        <button type="submit">Submit</button>
      </p>
    </form>
  </body>
  <script>
    const handleSubmit = (e) => {
      e.preventDefault()
      let myForm = document.getElementById('myForm');
      let formData = new FormData(myForm)
      fetch('/', {
    	method: 'POST',
    	body: formData
      })
    	.then(() => alert('success!'))
    	.catch((error) => alert(error))
    }

    document.querySelector("form").addEventListener("submit", handleSubmit);
  </script>
</html>

Please let us know if you’re seeing something different.

Fascinating - it did. Now - while I don’t think my Vue code is perfect, I honestly didn’t expect an issue there. And oddly, by using a new name and it working, maybe it’s something else. Doing a test now.

Nope, it still won’t work for me. I noticed you post to /. I tried that as well and it doesn’t help. I also notice you aren’t encoding your formdata - I’ll give that a shot next.

Also - if you are copying the form data with FormData(myForm), you are not passing a value called form-name with the name of the form. I thought that was required?

EDIT: Never mind - forgot that the hidden form field is added automatically.

AHAH! That’s getting me somewhere. When I view source on form3.html vs form5.html (what I called your code), your code has the hidden form tag. Netlify is not “seeing” my form tag:

<form method="post" name="My Contact Form 7" action="/" id="myForm"  @submit.prevent="sendForm" ref="formTag" data-netlify="true">

Why would it miss it?

EDIT! AHAH! So when I remove @submit.prevent="sendForm" ref="formTag" Netlify “sees” the form and adds the hidden form tag. Of course that breaks the Vue application. So is the regex that yall use somehow ‘confused’ by the Vue-ism? It shouldn’t be - but that would be a real bug you could test, right?

EDIT: It looks to be specifically @submit.prevent="sendForm" that breaks the regex.

Hey @cfjedimaster,
We just tested NetlifyTestingZone/form3.html at master · cfjedimaster/NetlifyTestingZone · GitHub and the submission was successfully received. Please let us know if you’re seeing something different.

That’s because I updated it with a fix. :slight_smile: Can you please test with the original code where @submit is used in the form tag? I believe this breaks the regex (I assume) you look when scanning for netlify forms.

Hey @cfjedimaster,
Sorry for the delay here, got a bit lost in all the different issues and form versions here. Could you please share a live version of the form you would like us to investigate? Thanks!

New form is here: NetlifyTestingZone/form10.html at master · cfjedimaster/NetlifyTestingZone · GitHub
Online it is here: Special Contact Form

If you view source, you will see Netlify didn’t “recognize” the form tag needed to be processed.

Hey @cfjedimaster,
This is what @luke was getting at earlier: that because you’re no longer submitting a pure HTML form at this point (that’s what you’re doing by adding Javascript inside the form tag), you will need to also include a pure HTML replica of the form in order for our form bots to pick it up:

So the body of your html file would look like this:

	<h2>Contact Form</h2>

	<form type="hidden" name="My Contact Form 10" data-netlify="true" >
		<input type="hidden" name="name">
		<input type="hidden" name="email">
		<input type="hidden" name="comments">
	</form>

	<form method="post" name="My Contact Form 10" action="/" id="myForm" @submit.prevent="sendForm" ref="formTag">
	<p>
		<label for="name">Name:</label>
		<input type="text" name="name" id="name" v-model="name">
	</p>
	<p>
		<label for="email">Email:</label>
		<input type="email" name="email" id="email" v-model="email">
	</p>
	<p>
		<label for="comments">Comments:</label><br/>
		<textarea name="comments" id="comments" v-model="comments"></textarea>
	</p>
	<p>
		<input type="submit">
	</p>
	</form>

I think about Netlify forms as having two different components:

  1. we need a version of your form that is legible to our HTML parser, that we can use to say “we’re expecting submissions to the form with x name, in y shape”;
  2. and then, apart from that, you need code to handle inputs and send them to that form that we set up for you, in the format that we expect.

In a perfect world (i.e., with pure HTML forms), these two components live in the same form, with very little additional configuration. But when they don’t, we have to do things like add a hidden form as I did above.

Let us know if this helps or if you have other questions.