0

I want to create a json on a html form:

<form enctype='application/json'>
  <input name='pet[0][species]' value='Dahut'>
  <input name='pet[0][name]' value='Hypatia'>
  <input name='pet[1][species]' value='Felis Stultus'>
  <input name='pet[1][name]' value='Billie'>
</form>

From the html above, I expect to get the following json:

// produces
{
    "pet":  [
        {
            "species":  "Dahut"
        ,   "name":     "Hypatia"
        }
    ,   {
            "species":  "Felis Stultus"
        ,   "name":     "Billie"
        }
    ]
}

Without the need of the following code:

  function serializeForm()
  {
    var jsonData = $('form').serializeArray();
    var jsonString = JSON.stringify(jsonData);
    $('#result').html(jsonString);
  }

But, unfortunately, I'm getting the following json:

[{"name":"pet[0][species]","value":"Dahut"},{"name":"pet[0][name]","value":"Hypatia"},{"name":"pet[1][species]","value":"Felis Stultus"},{"name":"pet[1][name]","value":"Billie"}]
Ricardo Rocha
  • 14,612
  • 20
  • 74
  • 130
Paul
  • 17
  • 2
  • 8
  • You expect wrong results of function. It would be problem if `.serialize` would do `?Hypatia=Dahut` and not `?pet[0][species]=Dahut`. You can create your own loop that transforms form data to your desired multi-dimensional array – Justinas Jul 26 '19 at 08:37
  • maybe this post is helpful https://stackoverflow.com/questions/11376184/jquery-serializearray-key-value-pairs – Nidhin Joseph Jul 26 '19 at 09:01

3 Answers3

1

You could iterate over the array elements and construct an object with the data on the expected format,

let data = {};

$form.serializeArray().forEach(field => {

  // Work on the data here to get the expected result

});

return data;

But, in my opinion, if you are willing to add some extra HTML to your form, the result would be more sustainable code.

If you are generating the form with data from the database, using a server side application, you could add two data fields and use them to extract the data in the expected format, something like this would work.

function serializeForm() {
  let jsonData = {
    pet: []
    },
    i = 0,
    $inputs = $('input[data-pet-id=' + i + ']');

  while ($inputs.length) {

    let pet = {
      species: $inputs.filter('input[data-field="species"]').val(),
      name: $inputs.filter('input[data-field="name"]').val()
    };

    jsonData.pet[i] = pet;

    i++;
    $inputs = $('input[data-pet-id=' + i + ']');

  }

  console.log(jsonData);
  
  $('#result').html(JSON.stringify(jsonData));
}

$('document').ready(() => {
  serializeForm();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<form id='my-form' enctype='application/json'>
  <input name='pet[0][species]' value='Dahut' data-pet-id="0" data-field='species'>
  <input name='pet[0][name]' value='Hypatia' data-pet-id="0" data-field='name'>
  <input name='pet[1][species]' value='Felis Stultus' data-pet-id="1" data-field='species'>
  <input name='pet[1][name]' value='Billie' data-pet-id="1" data-field='name'>
</form>

<div id="result">Working...</div>

The second solution should be more sustainable on the long run, assuming you are generating the HTML programatically.

Raul Sauco
  • 2,645
  • 3
  • 19
  • 22
  • thank you . It works for me almost perfect for me. additional question: how to nest additional array and get something like that: ```{"pet":[ { "nestedJson1": { "name001":"xxx", "name002": "xxx" }, "nestedJson2": { "name003": "xxx", "name004": "xxx" } } ]}``` – Paul Jul 26 '19 at 11:00
  • @Paul that depends on the structure of your form and the method that you would use to determine which *names* go on which *json objects*, but, costructing the JSON object is trivial once you have determined the structure that it should have. Just define the keys and get the values from the form. – Raul Sauco Jul 26 '19 at 11:14
  • Don't forget to accept the answer if it solved your problem. If you have a new problem is better to post a new question about it. Thanks! – Raul Sauco Jul 26 '19 at 11:15
0

That seems like an odd JSON object to build, but here's a way you can do it if you break out some of the information from the name attribute of the inputs into data attributes:

const petInputs = document.getElementsByName("pet");
const buildBtn = document.getElementById("build");

buildBtn.addEventListener("click", buildJSON);

function buildJSON(){

  // Defines `petsObj` for grouping information and `resultObj` for building result
  const petsObj = {},
        resultObj = { pet: [] };

  // Groups information by pet id# (separates unique pets from each other)
  for(let input of petInputs){
    const type = input.dataset.type, 
          id = input.dataset.id;
    if(!petsObj["id" + id]){ petsObj["id" + id] = {}; }
    petsObj["id" + id][type] = input.value;
  }

  // Counts the number of unique pets
  let petsCount = 0;
  for(let pet in petsObj){ petsCount++; }

  // Adds all pets to the `pet` property of the `json` object
  for(let i = 0; i < petsCount; i++){ resultObj.pet.push(petsObj["id" + i]); }

  // Prints and returns the JSON object
  console.log(resultObj);
  return(resultObj);
}
<input name="pet" data-type="species" data-id="0" value='Dahut'>
<input name="pet" data-type="name" data-id="0" value='Hypatia'><br />
<input name="pet" data-type="species" data-id="1" value='Felis Stultus'>
<input name="pet" data-type="name" data-id="1" value='Billie'><br />
<button id="build">Build JSON</button>
Cat
  • 4,141
  • 2
  • 10
  • 18
0

It don't seem that that enctype='application/json' is supported by browsers at this time (or anything else for that matter). From what I manage to read it was a suggestion to to the standard but was discarded some 4 years ago due to security/performance concerns.

Also I think the following code is a simpler way of doing (just doing it in one step)

$('#result').html(JSON.stringify($("#form").serializeArray()));

Griffin
  • 785
  • 5
  • 13