Author avatar

Gaurav Singhal

Formspree AJAX with ES6

Gaurav Singhal

  • Jul 22, 2019
  • 8 Min read
  • 68 Views
  • Jul 22, 2019
  • 8 Min read
  • 68 Views
Web Development

Introduction

In this guide, we are going to look into Formspree - a service that grants us simple form submission handling. We will see how we can submit the form to Formspree using ES6 syntax in React.

Formspree

When you are building static sites, you will come across numerous challenges surrounding how to deal with dynamic content, or form submissions. Well, perhaps you'd suggest for contact form submission that we can have a "mailto" link in the form action. We can, but that won't be an excellent experience for the user. The users will be required to switch into their email client and then they will also have to hit the send button- that's too much work to contact someone.

Formspree is the best service for static sites that don't have a backend to handle the form submissions. It is useful for portfolio sites and startups that don't want to invest much. Unlike other alternatives, like Google Form, we don't need to sacrifice the look of our website by embedding forms from external sources using an iframe that doesn't fit in with our User Interface (UI) for contact forms. We can make the form on our own that fits well with our site.

Formspree only requires us to have an action attribute that points to their URL. The URL format is https://formspree.io/{your email} and all the forms will be submitted to your email. When the form is submitted for the first time, Formspree will send a confirmation email. Make sure that you confirm by clicking the link in the email to receive form submissions from your website.

Let's Build the Contact Form

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<form action="https://formspree.io/[email protected]" method="POST">
    <div className="input-group">
    <label htmlFor="email">E-mail Address</label>
    <input
        type="email"
        name="email"
        id="email"
        value={this.state.values.email}
        onChange={this.handleInputChange}
        title="Email"
        required
    />
    </div>
    <div className="input-group">
    <label htmlFor="message">Message</label>
    <textarea
        name="message"
        id="message"
        onChange={this.handleInputChange}
        title="password"
        required
    >{this.state.values.message}</textarea>
    </div>
    <button type="submit">Send</button>
</form>
jsx

For sending the form data using AJAX, we will have to add the submit handler and remove the action attribute.

1
2
3
4
<form onSubmit={this.submitForm} >
    ...
    <button type="submit">Send</button>
</form>
jsx

Like in my previous guide, Submit Form in React without jQuery AJAX we will have the state and handlers as follows:

1
2
3
4
5
6
7
8
this.state = {
    values: {
        email: "",
        message: ""
    },
    isSubmitting: false,
    isError: false
};
jsx
1
2
3
4
5
6
7
8
9
handleInputChange = e =>
    this.setState({
      values: { ...this.state.values, [e.target.name]: e.target.value }
    });

submitForm = e => {
    e.preventDefault();
    // fetch() - post data to formspree url
}
jsx

In my previous guide, we learned how we could submit form data using the fetch() API. For those of you who don't know what that is, it's the new Promise-based native method to make network requests.

1
2
3
4
5
6
7
fetch(url, {...options})
    .then(response => {
        // resolve the data
    })
    .then(data => {
        // use the data
    });
javascript

For this guide, we will be using an external library - axios to make the network request for us.

Axios

The problem with fetch is that we require two steps to get the data and make use of it. Suppose, if we have to upload files, fetch won't get us the upload progress. So for such scenarios, we can use Axios.

Internally Axios uses the XML HTTP Request (XHR) and abstracts it's the complex syntax for us and provides a much cleaner method.

Basic Usage

GET Request Example

1
2
3
4
5
6
7
axios.get(url, {...options})
    .then(response => {
        // handle success
    })
    .catch(error => {
        // handle error
    })
javascript

POST Request Example

1
2
3
4
5
6
7
axios.post(url, data, {...options})
    .then(response => {
        // handle success
    })
    .catch(error => {
        // handle error
    })
javascript

We can also use async/await with Axios:

1
2
3
4
5
6
7
8
const getData = async () => {
    try {
        const {data} = await axios.get(url);
        return data;
    } catch(err) {
        console.log(err);
    }
}
javascript

submitForm() Handler Using Axios

Now that we know about Axios and how to use its syntax, let's request the Formspree URL.

1
2
3
4
5
6
7
submitForm = async e => {
    e.preventDefault();
    try {
        const {data} = await axios.post("https://formspree.io/[email protected]", {...this.state.values});
    } catch (err) {
        console.log(err);
    }
jsx

Complete Code

To summarise all the code above, here's the complete source for this guide.

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import React, { Component } from "react";
import ReactDOM from "react-dom";

import axios from "axios";

import "./styles.css";

class ContactForm extends Component {
  constructor(props) {
    super(props);
    this.state = {
      values: {
        email: "",
        message: ""
      },
      isSubmitting: false,
      isError: false
    };
  }

  submitForm = async e => {
    e.preventDefault();
    console.log(this.state);
    this.setState({ isSubmitting: true });
    try {
        const {data} = await axios.post("https://formspree.io/[email protected]", {...this.state.values});
    } catch (err) {
        console.log(err);
    }

    setTimeout(
      () =>
        this.setState({
          isError: false,
          message: "",
          values: { email: "", password: "" }
        }),
      1600
    );
  };

  handleInputChange = e =>
    this.setState({
      values: { ...this.state.values, [e.target.name]: e.target.value }
    });

  render() {
    return (
      <div>
        <form onSubmit={this.submitForm}>
          <div className="input-group">
            <label htmlFor="email">E-mail Address</label>
            <input
              type="email"
              name="email"
              id="email"
              value={this.state.values.email}
              onChange={this.handleInputChange}
              title="Email"
              required
            />
          </div>
          <div className="input-group">
            <label htmlFor="message">Message</label>
            <textarea
              name="message"
              id="message"
              onChange={this.handleInputChange}
              title="password"
              required
            >{this.state.values.message}</textarea>
          </div>
          <button type="submit">Send</button>
        </form>
        <div className={`message ${this.state.isError && "error"}`}>
          {this.state.isSubmitting ? "Submitting..." : this.state.message}
        </div>
      </div>
    );
  }
}

function App() {
  return (
    <div className="App">
      <h1>Contact US</h1>
      <ContactForm />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
jsx

styles.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.App {
  font-family: sans-serif;
}
.input-group {
  margin-bottom: 10px;
}
.input-group label {
  display: block;
  margin-bottom: 5px;
}
button {
  border: none;
  padding: 8px 24px;
}
.message {
  margin-top: 20px;
  font-weight: 600;
}
.message.error {
  color: red;
}
css

Limitations

Unfortunately, Formspree doesn't allow AJAX calls to their URL and access to their API for free users. So, those users will have to make do with the action form attribute.

That's it from this guide. Until next time, keep hustling and code like a beast.

References

0