0

I have seen this method of serializing a form to JSON and it's working fine. My question is: How can I achieve this with pure JavaScript, without using any jQuery code? I am sorry if the question is dumb, but I'm still learning so if anyone can help me, I'll be grateful.

(function ($) {
    $.fn.serializeFormJSON = function () {

        var objects = {};
        var anArray = this.serializeArray();
        $.each(anArray, function () {
            if (objects[this.name]) {
                if (!objects[this.name].push) {
                    objects[this.name] = [objects[this.name]];
                }
                objects[this.name].push(this.value || '');
            } else {
                objects[this.name] = this.value || '';
            }
        });
        return objects;
    };
})(jQuery);

$('form').submit(function (e) {
    e.preventDefault();
    var data = $(this).serializeFormJSON();
    console.log(data);

    /* Object
        email: "value"
        name: "value"
        password: "value"
     */
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="#" method="post">
    <div>
        <label for="name">Name</label>
        <input type="text" name="name" id="name" />
    </div>
    <div>
        <label for="email">Email</label>
        <input type="text" name="email" id="email" />
    </div>
    <div>
        <label for="password">Password</label>
        <input type="password" name="password" id="password" />
    </div>
    <p>
        <input type="submit" value="Send" />
    </p>
</form>

P.S. Also in jQuery is this the right way to send multiple JSON objects from user input as One String, because I am searching for a way to do that?

2

4 Answers 4

1

You can try something like this:

    function formToJson(){
        var formElement = document.getElementsByTagName("form")[0],
            inputElements = formElement.getElementsByTagName("input"),
            jsonObject = {};
        for(var i = 0; i < inputElements.length; i++){
            var inputElement = inputElements[i];
            jsonObject[inputElement.name] = inputElement.value;

        }
        return JSON.stringify(jsonObject);
    }

This solution works only if you have a single form on the page, to make it more general the function could e.g. take the form element as an argument.

Sign up to request clarification or add additional context in comments.

Comments

1

You can use Array.reduce, something like

// get array of all fields and/or selects (except the button)
const getFields = () => Array.from(document.querySelectorAll("input, select"))
    .filter(field => field.type.toLowerCase() !== "button");

// get id, name or create random id from field properties
const getKey = field => field.name 
  || field.id 
  || `unknown-${Math.floor(1000 * Math.random()).toString(16)}`;

// get data, simple object
const getFormData = () => getFields()
    .reduce( (f2o, field) => ({...f2o, [getKey(field)]: field.value}), {} );

// log the result
const logResult = txt => document.querySelector("#result").textContent = txt;

// get data, array of field objects
const getMoreFormData = () => getFields()
  .reduce( (f2o, field) =>
    f2o.concat({
        id: field.id || "no id",
        name: field.name || "no name",
        idGenerated: getKey(field),
        type: field.type, 
        value: field.value }
      ),
    [] );

// handling for buttons
document.addEventListener("click", evt => {
  if (evt.target.nodeName.toLowerCase() === "button") {
    console.clear();
    logResult(/simple/.test(evt.target.textContent)
     ? JSON.stringify(getFormData(), null, " ")
     : JSON.stringify(getMoreFormData(), null, " ")
    );
  }
} );
<form action="#" method="post">
  <div>
    <label for="name">Name</label>
    <input type="text" name="name" id="name" value="Pete"/>
  </div>
  <div>
    <label for="email">Email</label>
    <input type="text" name="email" id="email" value="[email protected]"/>
  </div>
  <div>
    <label for="password">Password</label>
    <input type="password" name="password" id="password" />
  </div>
  <div>
    <label>Field without name or id</label>
    <input type="number" value="12345" />
  </div>
</form>

<p>
  <button>Data simple object</button> <button>Data fields array</button>
</p>

<pre id="result"></pre>

Comments

0

Remember that for checkboxes, value attribute can be either on or off string. This is unwanted. Here is my solution, based on this codepen.

let json = Array.from(form.querySelectorAll('input, select, textarea'))
    .filter(element => element.name)
    .reduce((json, element) => {
        json[element.name] = element.type === 'checkbox' ? element.checked : element.value;
        return json;
    }, {});

OR

let json = {};
Array.from(form.querySelectorAll('input, select, textarea'))
    .filter(element => element.name)
    .forEach(element => {
        json[element.name] = element.type === 'checkbox' ? element.checked : element.value;
    });

OR (with typescript)

export type FormJson = {[key: string]: boolean | string};

export const toJson = (form: HTMLFormElement): FormJson => 
    Array.from(form.querySelectorAll<HTMLFormElement>('input, select, textarea'))
        .filter(element => element.name)
        .reduce<FormJson>((json, element) => {
            json[element.name] = element.type === 'checkbox' ? element.checked : element.value;
            return json;
        }, {});

Comments

0

To serialize your form you can do this (note that I added an onsubmit in the form tag):

HTML and JavaScript:

function serializeForm(e) {
    e.preventDefault(); // prevent the page to reload

    let form = e.target; // get the form itself
    let data = new FormData(form); // serialize input names and values

    let objSerializedForm = {}; // creating a new object
    for (let [name, value] of data) { // iterating the FormData data
        objSerializedForm[name] = value; // appending names and values to obj
    }
    
    console.log(objSerializedForm);
}
<form action="#" method="post" onsubmit="serializeForm(event)">
    <div>
        <label for="name">Name</label>
        <input type="text" name="name" id="name" />
    </div>
    <div>
        <label for="email">Email</label>
        <input type="text" name="email" id="email" />
    </div>
    <div>
        <label for="password">Password</label>
        <input type="password" name="password" id="password" />
    </div>
    <p>
        <input type="submit" value="Send" />
    </p>
</form>

Than you can do whatever you want with your objSerializedForm, getting each value by calling objSerializedForm.name.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.