Proper way to submit netlify forms with SSR frameworks like svelte / sapper

Hello!

I am currently trying to integrate my simple test app with Netlify forms. I am using svelte with sapper. This is the app:

The code for the form is:

<form name="contact" method="POST" data-netlify="true">
    <p>
      <label>Your Name/Organization: <input type="text" name="name" /></label>   
    </p>
    <p>
      <label>Your Email: <input type="email" name="email" /></label>
    </p>
  
    <p>
      <label>Message: <textarea name="message"></textarea></label>
    </p>
    <p>
      <button type="submit">Reach out</button>
    </p>
  </form>

When I submit, I get a 404 error from Netlify with the back button.

In svelte, I can override the default behavior of the button pretty easily, but wouldnt I still have to post the request? I googled and searched the forums and I couldn’t find an answer specific to posting directly to Netlify forms via javascript or some other solution other than the default HTML behavior.

So two questions:

  1. Am I even doing it right? (lol)
  2. Will I need to implement a javascript solution to post data to the Netlify form API using svelte? If so, how?

Thank you for your time, I am really enjoying the platform and am currently trying to build a business model around it.

Have a great weekend! Thanks again.

Does this help: Form 404 - Static Form in Svelte / Sapper - #2 by jen?

Depends on you. JavaScript form submission via AJAX will allow you to submit the form data without the page getting refreshed. You then have to manipulate your DOM to show/hide success/error messages. If you are fine with the page reloading, you don’t need to.

Regarding the how part, the form docs already have a jQuery example.

Here’s a rough vanilla JS example:

/* assumed that your form will have a class named 'contact-form' */
var form = document.querySelector('.contact-form');

/* form submission handler */
form.addEventListener('submit', function(e)
  {
    e.preventDefault(); // disables the default form submit action

    /* gathers form data to submit */
    var XHR = new XMLHttpRequest();
    var FD = new FormData(form);

    /* submission successful */
    XHR.addEventListener('load', function(event)
      {
        /* show your success message */
      }

    /* submission failed */
    XHR.addEventListener('error', function(event)
      {
        /* show your error message */
      }

    /* actually submits the form */
    XHR.open('POST', '#');
    XHR.send(FD);
  }
1 Like

Hello! Thank you for the reply. I tried the above via svelte coding and I get a 404 error on the post #. The data is loaded, but because of the SSR it doesn’t recognize the #. Here is the code:

<form class="content">
    <p>
        <label>Name<input type="text" bind:value={$user.name} /></label>
    </p>
    <p>
        <label>E-mail<input type="text" bind:value={$user.email} /></label>
    </p>
    <p>
        <label>Telephone<input type="text" bind:value={$user.phone} /></label>
    </p>

    <button on:click|preventDefault={submitForm}>Reach out</button>
</form>

<script>
    import { user } from "../store.js";

    let submitForm =(event)=>{
        
        event.preventDefault();

        var oReq = new XMLHttpRequest();
       
        oReq.open('POST','#');

        oReq.send($user);

    };
</script>

Im thinking because its SSR I will have to play around with component mounting or something to get the post to properly go through. Any other suggestions very much appreciated! :smiley:

The JavaScript one also won’t work unless the pure HTML one is working. Did the 404 error in your original form get resolved?

Also, I’m not familiar with Svelete’s way of working, but, as long as the HTML form is working normally and the script is loaded in the browser, it should work.

What I am realizing now is that I am using sapper, which is a framework that acts as a server of sorts, which is rendering my views. After googling, “post request from sapper” I am realizing this has nothing to do with netlify probably! Still, I will return when i figure it out and post my solution. Thank you!

1 Like

I havent figured it out, but so far I have figured out that just doing the standard form post with hidden field submits a form, however the body is empty. I found online that you can disable the service worker and it will work, but it didn’t. I also installed body-parser and made a JS file on my contact.svelte route that goes like this

export async function post(req, res, next) {
    /* Initializes */
    res.setHeader('Content-Type', 'application/json')
    /* Retrieves the data */
    var data = req.body
    /* Returns the result */
    return res.end(JSON.stringify(data))
  }

Although I don’t think this ever runs because when.I run a fetch request from the submit button it just gives me a 404 error every time instantly. I’ve tried all sorts of stuff in the fetch url and nothing changes the 404.

I am at a complete loss really. I might try this with just svelte and see how well it works…

Hey @ladams4 :wave:t2:

Is your code base / repository for your site open source / publicly viewable? Happy to take a look for you; Forms can be finicky with some of these more progressive / dynamic-front-end SSGs :slight_smile:

–
Jon

Hello! It is now!

https://github.com/levyadams/nebula

thank you very much! I am currently stumped!

Thanks! So I don’t have a ton of time to dig into this right now, but here’s what I found on a quick glance.

https://github.com/levyadams/nebula/blob/ba3e74f78ce254a16a116bd9d62cf201a264d2d2/src/components/contactform.svelte#L19

You’re going to have problems submitting the form like this. You’ve set the Content-Type header correctly (form encoded) but the body isn’t actually form encoded content… and for that matter, I think it’s structurally invalid :thinking:

You’ll have to forgive me - I’m actually writing the part 2 right now which more directly pertains to this situation, but I just wrote this last night as a primer for how Netlify Forms works. I’d recommend giving it a read then making sure that your custom submit handler (above) is adhering to the spec of a Forms Listener - the content type, the body formatted correctly, and the form name being submitted within that url-encoded payload.

11-09-20 - A Primer on Netlify Forms Pt. 1

Let’s go from there :slight_smile: writing part 2 now so that will add more clarity once I’m done.

–
Jon

Hello! thank you.

I have read both posts, and everything else I can on the subject.

This is the newest post request

let submitForm =(event)=>{
    let formdata = new FormData();
    formdata.append('name',$user.name);
    formdata.append('email',$user.email);
    formdata.append('telephone',$user.telephone);
        fetch("/contact/", {
        method: "POST",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body: formdata,
      })
        .then(() => alert("Success!"))
        .catch(error => alert(error));

      event.preventDefault();
    }

Ive verified locally that the new form data is good. Everything seems like it should work. The form is submitted but I get a 404 still in the console. Im not sure what else to try to be honest. Thinking of redoing an app down the road with just svelte see if its a sapper deal or something.

Hey @ladams4,
When I “view source” on your contact form, I see that many fields are missing quotes:

                <form class='svelte-1j5unvj' method='POST' name='contact'>
                    <p class=svelte-1j5unvj><label class=svelte-1j5unvj>Name<input></label></p>
                    <p class=svelte-1j5unvj><label class=svelte-1j5unvj>E-mail<input></label></p>
                    <p class=svelte-1j5unvj><label class=svelte-1j5unvj>Telephone<input></label></p> <input
                        name=form-name type=hidden value=contact> <button type=submit>Reach out</button>
                </form>

Your input fields will also need the required name attribute, and you’ll need data-netlify="true" inside your opening form tag, like this:

                <form class='svelte-1j5unvj' method='POST' name='contact' data-netlify="true">
                    <p><label>Name<input name="name"></label></p>
                    <p><label>Email<input name="email"></label></p>
                    <p><label>Telephone<input name="telephone"></label></p>
                    <input name="form-name" type="hidden" value="contact">
                    <button type="submit">Reach out</button>
                </form>
1 Like

Hello!

So i am at like zero hour for a big trip this weekend and am trying to finish work for the client while I am gone so I have very little hope of testing this, but I wanted to reach out and thank you for taking the time to review this as it has been a huge bummer to me that it doesn’t work. I will update what happens when I get back from my trip worst case scenario. Have a great weekend. :slight_smile:

1 Like

Fingers crossed! If it doesn’t work, definitely let us know and we’ll keep trying to figure it out.

1 Like

Hello again!

The solution here was indeed that the values were wrong! Huge ultra massive props to @jen for the solution!

I simply used an ES6 variable casting dealio.

<script>
let form;
let submitForm =(event)=>{
    let formdata = new FormData();
    formdata.append('name',`${user.name}`); //notice we cast the store values as strings with the `${var}` syntax
    formdata.append('email',`${user.email}`);
    formdata.append('telephone',`${user.telephone}`);
        fetch("/contact/", {
        method: "POST",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body: formdata,
      })
        .then(() => alert("Success!"))
        .catch(error => alert(error));
      event.preventDefault();
    }
    import { user } from "../store.js";
</script>