Wondering is there a function in javascript without jquery or any framework that allows me to serialize the form and access the serialized version?
Wondering is there a function in javascript without jquery or any framework that allows me to serialize the form and access the serialized version?
Works in all browsers.
const formSerialize = formElement => {
const values = {};
const inputs = formElement.elements;
for (let i = 0; i < inputs.length; i++) {
values[inputs[i].name] = inputs[i].value;
}
return values;
}
const dumpValues = form => () => {
const r = formSerialize(form);
console.log(r);
console.log(JSON.stringify(r));
}
const form = document.querySelector('form');
dumpValues(form)();
form.addEventListener('change',dumpValues(form));
<form action="/my-handling-form-page" method="post">
<div>
<label for="name">Name:</label>
<input type="text" id="name" name="user_name" value="John">
</div>
<div>
<label for="mail">E-mail:</label>
<input type="email" id="mail" name="user_mail" value="john@jonhson.j">
</div>
<div>
<label for="interests">Interest:</label>
<select required="" id="interests" name="interests">
<option value="" selected="selected">- None -</option>
<option value="drums">Drums</option>
<option value="js">Javascript</option>
<option value="sports">Sports</option>
<option value="trekking">Trekking</option>
</select>
</div>
<div>
<label for="msg">Message:</label>
<textarea id="msg" name="user_message">Hello My Friend</textarea>
</div>
</form>
This could be done by very simple function as follows
function serialize(form) {
let requestArray = [];
form.querySelectorAll('[name]').forEach((elem) => {
requestArray.push(elem.name + '=' + elem.value);
});
if(requestArray.length > 0)
return requestArray.join('&');
else
return false;
}
serialized = serialize(document.querySelector('form'))
console.log(serialized);
<form>
<input type='text' name='fname' value='Johne'/>
<input type='text' name='lname' value='Doe'/>
<input type='text' name='contact[]' value='99999999'/>
<input type='text' name='contact[]' value='34423434345'/>
</form>
I've grabbed the entries() method of formData from @moison answer and from MDN it's said that :
The FormData.entries() method returns an iterator allowing to go through all key/value pairs contained in this object. The key of each pair is a USVString object; the value either a USVString, or a Blob.
but the only issue is that mobile browser (android and safari are not supported ) and IE and Safari desktop too
but basically here is my approach :
let theForm = document.getElementById("contact");
theForm.onsubmit = function(event) {
event.preventDefault();
let rawData = new FormData(theForm);
let data = {};
for(let pair of rawData.entries()) {
data[pair[0]] = pair[1];
}
let contactData = JSON.stringify(data);
console.warn(contactData);
//here you can send a post request with content-type :'application.json'
};
the code can be found here
Using JavaScript reduce function should do a trick for all browsers, including IE9 >:
Array.prototype.slice.call(form.elements) // convert form elements to array
.reduce(function(acc,cur){ // reduce
var o = {type : cur.type, name : cur.name, value : cur.value}; // get needed keys
if(['checkbox','radio'].indexOf(cur.type) !==-1){
o.checked = cur.checked;
} else if(cur.type === 'select-multiple'){
o.value=[];
for(i=0;i<cur.length;i++){
o.value.push({
value : cur.options[i].value,
selected : cur.options[i].selected
});
}
}
acc.push(o);
return acc;
},[]);
Live example bellow.
var _formId = document.getElementById('formId'),
formData = Array.prototype.slice.call(_formId.elements).reduce(function(acc,cur,indx,arr){
var i,o = {type : cur.type, name : cur.name, value : cur.value};
if(['checkbox','radio'].indexOf(cur.type) !==-1){
o.checked = cur.checked;
} else if(cur.type === 'select-multiple'){
o.value=[];
for(i=0;i<cur.length;i++){
o.value.push({
value : cur.options[i].value,
selected : cur.options[i].selected
});
}
}
acc.push(o);
return acc;
},[]);
// view
document.getElementById('formOutput').innerHTML = JSON.stringify(formData, null, 4);
<form id="formId">
<input type="text" name="texttype" value="some text">
<select>
<option value="Opt 1">Opt 1</option>
<option value="Opt 2" selected>Opt 2</option>
<option value="Opt 3">Opt 3</option>
</select>
<input type="checkbox" name="checkboxtype" value="Checkbox 1" checked> Checkbox 1
<input type="checkbox" name="checkboxtype" value="Checkbox 2"> Checkbox 2
<input type="radio" name="radiotype" value="Radio Btn 1"> Radio Btn 1
<input type="radio" name="radiotype" value="Radio Btn 2" checked> Radio Btn 2
<select multiple>
<option value="Multi 1" selected>Multi 1</option>
<option value="Multi 2">Saab</option>
<option value="Multi 3" selected>Multi 3</option>
</select>
</form>
<pre><code id="formOutput"></code></pre>
my way...
const myForm = document.forms['form-name']
myForm.onsubmit=e=>
{
e.preventDefault() // for testing...
let data = Array.from(new FormData(myForm))
.reduce((r,[k,v])=>{r[k]=v;return r},{})
/*_______________________________________ same code: for beginners
let data = {}
Array.from(new FormData(myForm), (entry) => { data[ entry[0] ] = entry[1]} )
________________________________________________________________*/
console.log(data)
//...
}
// supports IE8 and IE9
function serialize(form) {
var inputs = form.elements;
var array = [];
for(i=0; i < inputs.length; i++) {
var inputNameValue = inputs[i].name + '=' + inputs[i].value;
array.push(inputNameValue);
}
return array.join('&');
}
//using the serialize function written above
var form = document.getElementById("form");//get the id of your form. i am assuming the id to be named form.
var form_data = serialize(form);
var xhr = new XMLHttpRequest();
xhr.send(form_data);
//does not work with IE8 AND IE9
var form = document.querySelector('form');
var data = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.send(data);
Improving upon David Lemon's answer.
This converts form data to JSON and allows you to set the form from a data object.
const main = () => {
const form = document.forms['info'];
const data = {
"user_name" : "John",
"user_email" : "john@jonhson.com",
"user_created" : "2020-03-24",
"user_age" : 42,
"user_subscribed" : true,
"user_interests" : "sports",
"user_message" : "Hello My Friend"
};
populateForm(form, data);
updateJsonView(form);
form.addEventListener('change', (e) => updateJsonView(form));
}
const getFieldValue = (field, opts) => {
let type = field.getAttribute('type');
if (type) {
switch (type) {
case 'checkbox':
return field.checked;
case 'number':
return field.value.includes('.')
? parseFloat(field.value)
: parseInt(field.value, 10);
}
}
if (opts && opts[field.name] && opts[field.name].type) {
switch (opts[field.name].type) {
case 'int':
return parseInt(field.value, 10);
case 'float':
return parseFloat(field.value);
}
}
return field.value;
}
const setFieldValue = (field, value) => {
let type = field.getAttribute('type');
if (type) {
switch (type) {
case 'checkbox':
field.checked = value;
break;
default:
field.value = value;
break;
}
} else {
field.value = value;
}
}
const extractFormData = (form, opts) => {
return Array.from(form.elements).reduce((data, element) => {
return Object.assign(data, { [element.name] : getFieldValue(element, opts) });
}, {});
};
const populateForm = (form, data) => {
return Array.from(form.elements).forEach((element) => {
setFieldValue(element, data[element.name]);
});
};
const updateJsonView = (form) => {
let fieldOptions = {};
let formData = extractFormData(form, fieldOptions);
let serializedData = JSON.stringify(formData, null, 2);
document.querySelector('.json-view').textContent = serializedData;
};
main();
.form-field {
margin-bottom: 0.5em;
}
.form-field label {
display: inline-block;
font-weight: bold;
width: 7em;
vertical-align: top;
}
.json-view {
position: absolute;
top: 0.667em;
right: 0.667em;
border: thin solid grey;
padding: 0.5em;
white-space: pre;
font-family: monospace;
overflow: scroll-y;
max-height: 100%;
}
<form name="info" action="/my-handling-form-page" method="post">
<div class="form-field">
<label for="name">Name:</label>
<input type="text" id="name" name="user_name">
</div>
<div class="form-field">
<label for="mail">E-mail:</label>
<input type="email" id="mail" name="user_email">
</div>
<div class="form-field">
<label for="created">Date of Birth:</label>
<input type="date" id="created" name="user_created">
</div>
<div class="form-field">
<label for="age">Age:</label>
<input type="number" id="age" name="user_age">
</div>
<div class="form-field">
<label for="subscribe">Subscribe:</label>
<input type="checkbox" id="subscribe" name="user_subscribed">
</div>
<div class="form-field">
<label for="interests">Interest:</label>
<select required="" id="interests" name="user_interests">
<option value="" selected="selected">- None -</option>
<option value="drums">Drums</option>
<option value="js">Javascript</option>
<option value="sports">Sports</option>
<option value="trekking">Trekking</option>
</select>
</div>
<div class="form-field">
<label for="msg">Message:</label>
<textarea id="msg" name="user_message"></textarea>
</div>
</form>
<div class="json-view"></div>
Here is pure JavaScript approach:
var form = document.querySelector('form');
var data = new FormData(form);
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
}
};
xhttp.open("POST", "<YOUR-URL>", true);
xhttp.send(data);
}
here's my solution -
JsonStringifyForm: function(formId) {
let myForm = document.getElementById(formId);
let formData = new FormData(myForm);
const data = {}; // need to convert it before using not with XMLHttpRequest
for (let [key, val] of formData.entries()) {
Object.assign(data, { [key]: val });
}
return JSON.stringify(data);
}
You can use Object.fromEntries as follow
function parseForm(e) {
const formData = new FormData(e.target);
return Object.fromEntries(formData.entries());
}
I hope this will work
var serializeForm = (formElement) => {
const formData = {};
const inputs = formElement.elements;
for (let i = 0; i < inputs.length; i++) {
if(inputs[i].name!=="")
formData[inputs[i].name] = inputs[i].value;
}
return formData;
}
For debugging purposes this might help you:
function print_form_data(form) {
const form_data = new FormData(form);
for (const item of form_data.entries()) {
console.log(item);
}
return false;
}
I could be crazy but I'm finding these answers seriously bloated. Here's my solution
function serialiseForm(form) {
var input = form.getElementsByTagName("input");
var formData = {};
for (var i = 0; i < input.length; i++) {
formData[input[i].name] = input[i].value;
}
return formData = JSON.stringify(formData);
}
I like this library: https://github.com/macek/jquery-serialize-object (1.7KB in size)
Given a basic HTML form:
<form id="contact">
<input name="user[email]" value="jsmith@example.com">
<input name="user[pets][]" type="checkbox" value="cat" checked>
<input name="user[pets][]" type="checkbox" value="dog" checked>
<input name="user[pets][]" type="checkbox" value="bird">
<input type="submit">
</form>
.serializeObject — serializes the selected form into a JavaScript object
$('form#contact').serializeObject();
//=> {user: {email: "jsmith@example.com", pets: ["cat", "dog"]}}
Key styles
push — push a value to an array
<input name="foo[]" value="a">
<input name="foo[]" value="b">
$("form").serializeObject();
//=> {foo: [a, b]}
fixed — add a value to an array at a specified index
<input name="foo[2]" value="a">
<input name="foo[4]" value="b">
$("form").serializeObject();
//=> {foo: [, , "a", , "b"]}
named — adds a value to the specified key
<input name="foo[bar]" value="a">
<input name="foo[bof]" value="b">
<input name="hello" value="world">
$("form").serializeObject();
//=> {foo: {bar: "a", bof: "b"}, hello: "world"}
Similar library (more alive): https://github.com/marioizquierdo/jquery.serializeJSON
Similar library (very alive): https://github.com/brainfoolong/form-data-json With last one you could not just serialize data, but vice-versa: set values for form fields