How to send a JSON object using html form data
Asked Answered
K

11

203

So I've got this HTML form:

<html>
<head><title>test</title></head>
<body>
    <form action="myurl" method="POST" name="myForm">
        <p><label for="first_name">First Name:</label>
        <input type="text" name="first_name" id="fname"></p>

        <p><label for="last_name">Last Name:</label>
        <input type="text" name="last_name" id="lname"></p>

        <input value="Submit" type="submit" onclick="submitform()">
    </form>
</body>
</html>

Which would be the easiest way to send this form's data as a JSON object to my server when a user clicks on submit?

UPDATE: I've gone as far as this but it doesn't seem to work:

<script type="text/javascript">
    function submitform(){
        alert("Sending Json");
        var xhr = new XMLHttpRequest();
        xhr.open(form.method, form.action, true);
        xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
        var j = {
            "first_name":"binchen",
            "last_name":"heris",
        };
        xhr.send(JSON.stringify(j));

What am I doing wrong?

Kana answered 5/3, 2014 at 10:29 Comment(10)
Take a look at $.ajax and serialize in the jQuery API.Thence
Does it absolutely have to be a JSON object? What structure should the object have?Routine
@AnthonyGrist Yes it has to be a JSON cause it's addressed toward a ReST service.Kana
What does “doesn't seem to work” mean? Remember, we can't see your screen.Madewell
@Konos5 - REST has nothing to do with JSON. It doesn't require that data be in any particular format.Endocranium
In the above example of your code, your json is incorrect. That might be causing an issue.Cushiony
If you want to test the security of a web application against CSRF, there is a hack to send JSON using an HTML form: #19447044Discord
Here's a library that I created to do just this: github.com/keithhackbarth/submitAsJSONAlsworth
Use enctype <form enctype='application/json'> :) P.S. question marked as too broad but it is not, please update question and add answer to it.Petronel
line xhr.open(form.method, form.action, true); - form where this function should get the variable form?Spermary
E
184

Get complete form data as array and json stringify it.

var formData = JSON.stringify($("#myForm").serializeArray());

You can use it later in ajax. Or if you are not using ajax; put it in hidden textarea and pass to server. If this data is passed as json string via normal form data then you have to decode it. You'll then get all data in an array.

$.ajax({
  type: "POST",
  url: "serverUrl",
  data: formData,
  success: function(){},
  dataType: "json",
  contentType : "application/json"
});
Endorsement answered 5/3, 2014 at 10:35 Comment(1)
You've tagged question with jQuery. So are you using it ? with $.ajax it's really easy to pass this data.Endorsement
E
74

HTML provides no way to generate JSON from form data.

If you really want to handle it from the client, then you would have to resort to using JavaScript to:

  1. gather your data from the form via DOM
  2. organise it in an object or array
  3. generate JSON with JSON.stringify
  4. POST it with XMLHttpRequest

You'd probably be better off sticking to application/x-www-form-urlencoded data and processing that on the server instead of JSON. Your form doesn't have any complicated hierarchy that would benefit from a JSON data structure.


Update in response to major rewrite of the question…

  • Your JS has no readystatechange handler, so you do nothing with the response
  • You trigger the JS when the submit button is clicked without cancelling the default behaviour. The browser will submit the form (in the regular way) as soon as the JS function is complete.
Escudo answered 5/3, 2014 at 10:33 Comment(0)
V
18

Use FormData API

  1. Capture the form data using FormData API formData= new FormData(form)
  2. Convert it into JSON using JSON.stringify(Object.fromEntries(formData))
  3. Send this strigified json as ajax payload
var form = document.getElementById('myForm');
form.onsubmit = function(event){
        var xhr = new XMLHttpRequest();
        var formData = new FormData(form);
        //open the request
        xhr.open('POST','http://localhost:7000/tests/v1.0/form')
        xhr.setRequestHeader("Content-Type", "application/json");

        //send the form data
        xhr.send(JSON.stringify(Object.fromEntries(formData)));

        xhr.onreadystatechange = function() {
            if (xhr.readyState == XMLHttpRequest.DONE) {
                form.reset(); //reset form after AJAX success or do something else
            }
        }
        //Fail the onsubmit to avoid page refresh.
        return false; 
    }

Taken from an article I wrote here: https://metamug.com/article/html5/ajax-form-submit.html

Vapor answered 29/9, 2021 at 10:15 Comment(1)
There are edge cases (multi-selects) where Object.fromEntries(formData) does not fetch all of the form data.Markova
H
10

You can try something like:

<html>
<head>
    <title>test</title>
</head>

<body>
    <form id="formElem">
        <input type="text" name="firstname" value="Karam">
        <input type="text" name="lastname" value="Yousef">
        <input type="submit">
    </form>
    <div id="decoded"></div>
    <button id="encode">Encode</button>
    <div id="encoded"></div>
</body>
<script>
    encode.onclick = async (e) => {
        let response = await fetch('http://localhost:8482/encode', {
                method: 'GET',
                headers: {
                    'Content-Type': 'application/json',
                },
        })

        let text = await response.text(); // read response body as text
        data = JSON.parse(text);
        document.querySelector("#encoded").innerHTML = text;
      //  document.querySelector("#encoded").innerHTML = `First name = ${data.firstname} <br/> 
      //                                                  Last name = ${data.lastname} <br/>
      //                                                  Age    = ${data.age}`
    };

    formElem.onsubmit = async (e) => {
      e.preventDefault();
      var form = document.querySelector("#formElem");
     // var form = document.forms[0];

        data = {
          firstname : form.querySelector('input[name="firstname"]').value,
          lastname : form.querySelector('input[name="lastname"]').value,
          age : 5
        }

        let response = await fetch('http://localhost:8482/decode', {
                method: 'POST', // or 'PUT'
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(data),
        })

        let text = await response.text(); // read response body as text
        document.querySelector("#decoded").innerHTML = text;
    };
</script>
</html>
Hatfield answered 4/8, 2020 at 21:15 Comment(0)
L
4

you code is fine but never executed, cause of submit button [type="submit"] just replace it by type=button

<input value="Submit" type="button" onclick="submitform()">

inside your script; form is not declared.

let form = document.forms[0];
xhr.open(form.method, form.action, true);
Lavalley answered 5/4, 2019 at 2:57 Comment(1)
Exactly type="button" is very important, if not use then it redirect with url params.Slowdown
V
4

I'm late but I need to say for those who need an object, using only html, there's a way. In some server side frameworks like PHP you can write the follow code:

<form action="myurl" method="POST" name="myForm">
        <p><label for="first_name">First Name:</label>
        <input type="text" name="name[first]" id="fname"></p>

        <p><label for="last_name">Last Name:</label>
        <input type="text" name="name[last]" id="lname"></p>

        <input value="Submit" type="submit">
    </form>

So, we need setup the name of the input as object[property] for got an object. In the above example, we got a data with the follow JSON:

{
"name": {
  "first": "some data",
  "last": "some data"
 }
}
Varlet answered 3/3, 2020 at 2:31 Comment(2)
I have not tested this, but this seems also to be a good solution.Delogu
this does not post json but plain form data. Framework conversta that for you. I am surprised that this is upvoted so much.Monocotyledon
C
3

If you want to use pure javascript in 2022...

const ajax = async (config) => {
    const request = await fetch(config.url, {
        method: config.method,
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(config.payload)
    });
    response = await request.json();
    console.log('response', response)
    return response
}

// usage
response = ajax({
    method: 'POST',
    url: 'example.com',
    payload: {"name": "Stackoverflow"}
})
Cyclograph answered 30/8, 2022 at 10:4 Comment(0)
S
1

Well came across this again and there is no fetch copy pasta so though id add my own solution that I dug up.

This uses vanilla fetch and built in browser features.

/**
 * Helper function for POSTing data as JSON with fetch.
 *
 * @param {Object} options
 * @param {string} options.url - URL to POST data to
 * @param {FormData} options.formData - `FormData` instance
 * @return {Object} - Response body from URL that was POSTed to
 */
var postFormDataAsJson = async({
  url,
  formData
}) => {
  const plainFormData = Object.fromEntries(formData.entries());
  const formDataJsonString = JSON.stringify(plainFormData);

  const fetchOptions = {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
    },
    body: formDataJsonString,
  };


  alert("about to post" + formDataJsonString)
  const response = await fetch(url, fetchOptions);

  if (!response.ok) {
    const errorMessage = await response.text();
    throw new Error(errorMessage);
  }

  return response.json();
}
/**
 * Event handler for a form submit event.
 * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/submit_event
 * @example const exampleForm = document.getElementById("example-form");
 *          exampleForm.addEventListener("submit", handleFormSubmit);
 * @param {SubmitEvent} event
 */
var handleFormSubmit = async(event) => {
  event.preventDefault();
  const form = event.currentTarget;
  const url = form.action;

  try {
    const formData = new FormData(form);
    const responseData = await postFormDataAsJson({
      url,
      formData
    });
    console.log({
      responseData
    });
  } catch (error) {
    console.error(error);
  }
}

document.querySelector("form[name='myForm']")
  .addEventListener("submit", handleFormSubmit)
<html>

<head>
  <title>test</title>
</head>

<body>
  <form action="myurl" method="POST" name="myForm">
    <p><label for="first_name">First Name:</label>
      <input type="text" name="first_name" id="fname"></p>

    <p><label for="last_name">Last Name:</label>
      <input type="text" name="last_name" id="lname"></p>

    <input value="Submit" type="submit"> 
    </form>
  </body>

  </html>

sauces

https://bsjs.sgol.pub/doc/public_src_bs.js#line977

postFormDataAsJson jsdoc

less form dependent sendJson

Solanaceous answered 5/11, 2023 at 4:28 Comment(0)
W
0

The micro-library field-assist does exactly that: collectValues(formElement) will return a normalized json from the input fields (that means, also, checkboxes as booleans, selects as strings,etc).

Warner answered 8/12, 2020 at 16:30 Comment(0)
L
0

We can attach file and json in the following way

const api = (app, body) => getOptions({
    body,
    headers: {
        'Content-Type': 'application/json',
    },
    url: 'http://localhost:2030'
})

function multiPart(payload) {
    const formData = new FormData()
    formData.append('fileNames', payload.attachments)
    formData.append('fixedIncomeSubAccountRequest', JSON.stringify(payload.body))
    return formData
}

api(app, multiPart(payload)).then(response => console.log(respone))
Lallage answered 19/12, 2023 at 15:27 Comment(0)
G
-2

I found a way to pass a JSON message using only a HTML form.

This example is for GraphQL but it will work for any endpoint that is expecting a JSON message.

GrapqhQL by default expects a parameter called operations where you can add your query or mutation in JSON format. In this specific case I am invoking this query which is requesting to get allUsers and return the userId of each user.

{ 
 allUsers 
  { 
  userId 
  }
}

I am using a text input to demonstrate how to use it, but you can change it for a hidden input to hide the query from the user.

<html>
<body>
    <form method="post" action="http://localhost:8080/graphql">
        <input type="text" name="operations" value="{&quot;query&quot;: &quot;{ allUsers { userId } }&quot;, "variables":  {}}"/>
        <input type="submit" />
    </form>
</body>
</html>

In order to make this dynamic you will need JS to transport the values of the text fields to the query string before submitting your form. Anyway I found this approach very interesting. Hope it helps.

Gapeworm answered 20/11, 2020 at 0:2 Comment(1)
This does not post json but single form input with json value - that is a big differenceMonocotyledon

© 2022 - 2024 — McMap. All rights reserved.