ฉันจะแปลงรายการจากFormData
วัตถุHTML5 เป็น JSON ได้อย่างไร
วิธีแก้ปัญหาไม่ควรใช้ jQuery นอกจากนี้ไม่ควรทำให้เป็นอนุกรมของFormData
วัตถุทั้งหมดแต่เฉพาะรายการคีย์ / ค่าเท่านั้น
ฉันจะแปลงรายการจากFormData
วัตถุHTML5 เป็น JSON ได้อย่างไร
วิธีแก้ปัญหาไม่ควรใช้ jQuery นอกจากนี้ไม่ควรทำให้เป็นอนุกรมของFormData
วัตถุทั้งหมดแต่เฉพาะรายการคีย์ / ค่าเท่านั้น
คำตอบ:
คุณยังสามารถใช้forEach
กับFormData
วัตถุได้โดยตรง:
var object = {};
formData.forEach(function(value, key){
object[key] = value;
});
var json = JSON.stringify(object);
และสำหรับผู้ที่ชื่นชอบโซลูชันเดียวกันกับฟังก์ชัน ES6 arrow :
var object = {};
formData.forEach((value, key) => object[key] = value);
var json = JSON.stringify(object);
และสำหรับผู้ที่ต้องการการสนับสนุนสำหรับรายการแบบเลือกหลายรายการหรือองค์ประกอบแบบฟอร์มอื่น ๆ ที่มีค่าหลายค่า(เนื่องจากมีความคิดเห็นมากมายด้านล่างคำตอบเกี่ยวกับปัญหานี้ฉันจะเพิ่มวิธีแก้ไขที่เป็นไปได้) :
var object = {};
formData.forEach((value, key) => {
// Reflect.has in favor of: object.hasOwnProperty(key)
if(!Reflect.has(object, key)){
object[key] = value;
return;
}
if(!Array.isArray(object[key])){
object[key] = [object[key]];
}
object[key].push(value);
});
var json = JSON.stringify(object);
นี่คือซอที่แสดงให้เห็นถึงการใช้วิธีนี้ด้วยรายการเลือกหลายอย่างง่ายๆ
ตามหมายเหตุด้านข้างสำหรับผู้ที่ลงเอยที่นี่ในกรณีที่จุดประสงค์ของการแปลงข้อมูลฟอร์มเป็น json คือการส่งผ่านคำขอ XML HTTP ไปยังเซิร์ฟเวอร์คุณสามารถส่งFormData
วัตถุได้โดยตรงโดยไม่ต้องแปลง ง่ายๆดังนี้:
var request = new XMLHttpRequest();
request.open("POST", "http://example.com/submitform.php");
request.send(formData);
ดูยังใช้ FormData วัตถุบน MDN สำหรับการอ้างอิง :
ดังที่ได้กล่าวไว้ในความคิดเห็นด้านล่างคำตอบของฉันstringify
วิธีJSON จะไม่ทำงานนอกกรอบสำหรับวัตถุทุกประเภท สำหรับข้อมูลเพิ่มเติมเกี่ยวกับประเภทได้รับการสนับสนุนผมอยากจะหมายถึงส่วนของคำอธิบายในเอกสาร MDN JSON.stringify
ของ
ในคำอธิบายยังกล่าวถึงว่า:
หากค่ามีวิธี toJSON () มีหน้าที่กำหนดว่าข้อมูลใดจะถูกทำให้เป็นอนุกรม
ซึ่งหมายความว่าคุณสามารถจัดหาtoJSON
วิธีการทำให้เป็นอนุกรมของคุณเองด้วยตรรกะสำหรับการทำให้เป็นอนุกรมวัตถุที่กำหนดเองของคุณ เช่นเดียวกับที่คุณสามารถสร้างการสนับสนุนการทำให้เป็นอนุกรมสำหรับโครงสร้างวัตถุที่ซับซ้อนมากขึ้นได้อย่างรวดเร็วและง่ายดาย
<SELECT MULTIPLE>
และ<INPUT type="checkbox">
ชื่อเดียวกันโดยการแปลงค่าเป็นอาร์เรย์
JSON.stringify(Object.fromEntries(formData));
นั้นดีกว่ามาก
ในปี 2019 งานประเภทนี้กลายเป็นเรื่องง่ายสุด ๆ
JSON.stringify(Object.fromEntries(formData));
Object.fromEntries
: รองรับใน Chrome 73+, Firefox 63+, Safari 12.1
<select multiple>
หรือ<input type="checkbox">
😞
JSON.stringify(Object.fromEntries(formData.entries()));
นี่คือวิธีการทำในรูปแบบที่มีประโยชน์มากขึ้นโดยไม่ต้องใช้ไลบรารี
Array.from(formData.entries()).reduce((memo, pair) => ({
...memo,
[pair[0]]: pair[1],
}), {});
ตัวอย่าง:
document.getElementById('foobar').addEventListener('submit', (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const data = Array.from(formData.entries()).reduce((memo, pair) => ({
...memo,
[pair[0]]: pair[1],
}), {});
document.getElementById('output').innerHTML = JSON.stringify(data);
});
<form id='foobar'>
<input name='baz' />
<input type='submit' />
</form>
<pre id='output'>Input some value and submit</pre>
หากคุณมีหลายรายการที่มีชื่อเดียวกันตัวอย่างเช่นหากคุณใช้<SELECT multiple>
หรือมีหลายรายการที่<INPUT type="checkbox">
มีชื่อเดียวกันคุณจะต้องดูแลและสร้างอาร์เรย์ของค่า มิฉะนั้นคุณจะได้รับเฉพาะค่าสุดท้ายที่เลือก
นี่คือตัวแปร ES6 ที่ทันสมัย:
function formToJSON( elem ) {
let output = {};
new FormData( elem ).forEach(
( value, key ) => {
// Check if property already exist
if ( Object.prototype.hasOwnProperty.call( output, key ) ) {
let current = output[ key ];
if ( !Array.isArray( current ) ) {
// If it's not an array, convert it to an array.
current = output[ key ] = [ current ];
}
current.push( value ); // Add the new value to the array.
} else {
output[ key ] = value;
}
}
);
return JSON.stringify( output );
}
โค้ดเก่ากว่าเล็กน้อย (แต่ IE11 ยังไม่รองรับเนื่องจากไม่รองรับForEach
หรือentries
เปิดFormData
)
function formToJSON( elem ) {
var current, entries, item, key, output, value;
output = {};
entries = new FormData( elem ).entries();
// Iterate over values, and assign to item.
while ( item = entries.next().value )
{
// assign to variables to make the code more readable.
key = item[0];
value = item[1];
// Check if key already exist
if (Object.prototype.hasOwnProperty.call( output, key)) {
current = output[ key ];
if ( !Array.isArray( current ) ) {
// If it's not an array, convert it to an array.
current = output[ key ] = [ current ];
}
current.push( value ); // Add the new value to the array.
} else {
output[ key ] = value;
}
}
return JSON.stringify( output );
}
คุณสามารถบรรลุสิ่งนี้ได้โดยใช้FormData ()วัตถุออบเจ็กต์ FormData นี้จะถูกเติมด้วยคีย์ / ค่าปัจจุบันของฟอร์มโดยใช้คุณสมบัติชื่อของแต่ละองค์ประกอบสำหรับคีย์และค่าที่ส่งสำหรับค่า นอกจากนี้ยังเข้ารหัสเนื้อหาอินพุตไฟล์
ตัวอย่าง:
var myForm = document.getElementById('myForm');
myForm.addEventListener('submit', function(event)
{
event.preventDefault();
var formData = new FormData(myForm),
result = {};
for (var entry of formData.entries())
{
result[entry[0]] = entry[1];
}
result = JSON.stringify(result)
console.log(result);
});
for (const [key, value] of formData.entries())
ฟังก์ชั่นใช้งานง่าย
ฉันได้สร้างฟังก์ชันสำหรับสิ่งนี้
function FormDataToJSON(FormElement){
var formData = new FormData(FormElement);
var ConvertedJSON= {};
for (const [key, value] of formData.entries())
{
ConvertedJSON[key] = value;
}
return ConvertedJSON
}
ตัวอย่างการใช้งาน
var ReceivedJSON = FormDataToJSON(document.getElementById('FormId');)
ในโค้ดนี้ฉันได้สร้างตัวแปร JSON ว่างโดยใช้for
ลูปที่ฉันใช้key
s จาก formData Object ถึง JSON Keys ในทุกๆ Itration
คุณพบรหัสนี้ในไลบรารี JS ของฉันบน GitHub โปรดแนะนำฉันหากต้องการการปรับปรุงฉันได้วางโค้ดที่นี่https://github.com/alijamal14/Utilities/blob/master/Utilities.js
<select multiple>
<input type="checkbox">
โพสต์นี้มีอายุหนึ่งปีแล้ว ... แต่ฉันชอบคำตอบของ ES6 @dzuc จริงๆ อย่างไรก็ตามมันไม่สมบูรณ์เนื่องจากไม่สามารถจัดการการเลือกหรือช่องทำเครื่องหมายหลายช่องได้ สิ่งนี้ได้ชี้ไปแล้วและมีการเสนอโซลูชันโค้ด ฉันพบว่ามันหนักและไม่เหมาะสม ดังนั้นฉันจึงเขียน 2 เวอร์ชันโดยอิงจาก @dzuc เพื่อจัดการกับกรณีเหล่านี้:
let r=Array.from(fd).reduce(
(o , [k,v]) => (
(!o[k])
? {...o , [k] : v}
: {...o , [k] : [...o[k] , v]}
)
,{}
);
let obj=JSON.stringify(r);
เวอร์ชัน Hotshot หนึ่งบรรทัด:
Array.from(fd).reduce((o,[k,v])=>((!o[k])?{...o,[k]:v}:{...o,[k]:[...o[k],v]}),{});
[]
ส่วนต่อท้ายlet r=Array.from(fd).reduce(
(o , [k,v]) => (
(k.split('[').length>1)
? (k=k.split('[')[0]
, (!o[k])
? {...o , [k] : [v]}
: {...o , [k] : [...o[k] , v ]}
)
: {...o , [k] : v}
)
,{}
);
let obj=JSON.stringify(r);
เวอร์ชัน Hotshot หนึ่งบรรทัด:
Array.from(fd).reduce((o,[k,v])=>((k.split('[').length>1)?(k=k.split('[')[0],(!o[k])?{...o,[k]:[v]}:{...o,[k]:[...o[k],v]}):{...o,[k]:v}),{});
ตั้งแต่ครั้งที่แล้วที่ฉันเขียนกรณีที่สองก่อนหน้านี้ในที่ทำงานมีกรณีที่แบบฟอร์ม PHP มีช่องทำเครื่องหมายในหลายระดับ ฉันเขียนเคสใหม่เพื่อรองรับเคสก่อนหน้าและเคสนี้ ฉันสร้างตัวอย่างข้อมูลเพื่อแสดงกรณีนี้ให้ดีขึ้นผลลัพธ์จะแสดงบนคอนโซลสำหรับการสาธิตนี้แก้ไขตามความต้องการของคุณ พยายามเพิ่มประสิทธิภาพให้ดีที่สุดเท่าที่จะทำได้โดยไม่ลดทอนประสิทธิภาพ แต่ก็ส่งผลต่อความสามารถในการอ่านของมนุษย์ ใช้ประโยชน์จากการที่อาร์เรย์เป็นวัตถุและตัวแปรที่ชี้ไปยังอาร์เรย์จะถูกเก็บไว้เป็นข้อมูลอ้างอิง ไม่มี hotshot สำหรับคนนี้เป็นแขกของฉัน
let nosubmit = (e) => {
e.preventDefault();
const f = Array.from(new FormData(e.target));
const obj = f.reduce((o, [k, v]) => {
let a = v,
b, i,
m = k.split('['),
n = m[0],
l = m.length;
if (l > 1) {
a = b = o[n] || [];
for (i = 1; i < l; i++) {
m[i] = (m[i].split(']')[0] || b.length) * 1;
b = b[m[i]] = ((i + 1) == l) ? v : b[m[i]] || [];
}
}
return { ...o, [n]: a };
}, {});
console.log(obj);
}
document.querySelector('#theform').addEventListener('submit', nosubmit, {capture: true});
<h1>Multilevel Form</h1>
<form action="#" method="POST" enctype="multipart/form-data" id="theform">
<input type="hidden" name="_id" value="93242" />
<input type="hidden" name="_fid" value="45c0ec96929bc0d39a904ab5c7af70ef" />
<label>Select:
<select name="uselect">
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
</select>
</label>
<br /><br />
<label>Checkboxes one level:<br/>
<input name="c1[]" type="checkbox" checked value="1"/>v1
<input name="c1[]" type="checkbox" checked value="2"/>v2
<input name="c1[]" type="checkbox" checked value="3"/>v3
</label>
<br /><br />
<label>Checkboxes two levels:<br/>
<input name="c2[0][]" type="checkbox" checked value="4"/>0 v4
<input name="c2[0][]" type="checkbox" checked value="5"/>0 v5
<input name="c2[0][]" type="checkbox" checked value="6"/>0 v6
<br/>
<input name="c2[1][]" type="checkbox" checked value="7"/>1 v7
<input name="c2[1][]" type="checkbox" checked value="8"/>1 v8
<input name="c2[1][]" type="checkbox" checked value="9"/>1 v9
</label>
<br /><br />
<label>Radios:
<input type="radio" name="uradio" value="yes">YES
<input type="radio" name="uradio" checked value="no">NO
</label>
<br /><br />
<input type="submit" value="Submit" />
</form>
Array.from(fd).reduce((obj, [k, v]) => ({...obj, [k]: v}), {});
hotshot version es2018
หากคุณต้องการการสนับสนุนสำหรับการจัดลำดับฟิลด์ที่ซ้อนกันซึ่งคล้ายกับวิธีที่ PHP จัดการกับฟิลด์ในรูปแบบคุณสามารถใช้ฟังก์ชันต่อไปนี้
function update(data, keys, value) {
if (keys.length === 0) {
// Leaf node
return value;
}
let key = keys.shift();
if (!key) {
data = data || [];
if (Array.isArray(data)) {
key = data.length;
}
}
// Try converting key to a numeric value
let index = +key;
if (!isNaN(index)) {
// We have a numeric index, make data a numeric array
// This will not work if this is a associative array
// with numeric keys
data = data || [];
key = index;
}
// If none of the above matched, we have an associative array
data = data || {};
let val = update(data[key], keys, value);
data[key] = val;
return data;
}
function serializeForm(form) {
return Array.from((new FormData(form)).entries())
.reduce((data, [field, value]) => {
let [_, prefix, keys] = field.match(/^([^\[]+)((?:\[[^\]]*\])*)/);
if (keys) {
keys = Array.from(keys.matchAll(/\[([^\]]*)\]/g), m => m[1]);
value = update(data[prefix], keys, value);
}
data[prefix] = value;
return data;
}, {});
}
document.getElementById('output').textContent = JSON.stringify(serializeForm(document.getElementById('form')), null, 2);
<form id="form">
<input name="field1" value="Field 1">
<input name="field2[]" value="Field 21">
<input name="field2[]" value="Field 22">
<input name="field3[a]" value="Field 3a">
<input name="field3[b]" value="Field 3b">
<input name="field3[c]" value="Field 3c">
<input name="field4[x][a]" value="Field xa">
<input name="field4[x][b]" value="Field xb">
<input name="field4[x][c]" value="Field xc">
<input name="field4[y][a]" value="Field ya">
<input name="field5[z][0]" value="Field z0">
<input name="field5[z][]" value="Field z1">
<input name="field6.z" value="Field 6Z0">
<input name="field6.z" value="Field 6Z1">
</form>
<h2>Output</h2>
<pre id="output">
</pre>
วิธี FormData .entries
และfor of
การแสดงออกไม่ได้รับการสนับสนุนใน IE11 และ Safari
นี่คือเวอร์ชันที่เรียบง่ายกว่าเพื่อรองรับ Safari, Chrome, Firefox และ Edge
function formDataToJSON(formElement) {
var formData = new FormData(formElement),
convertedJSON = {};
formData.forEach(function(value, key) {
convertedJSON[key] = value;
});
return convertedJSON;
}
คำเตือน:คำตอบนี้ใช้ไม่ได้ใน IE11
FormData ไม่มีforEach
เมธอดใน IE11
ฉันยังคงค้นหาวิธีแก้ไขขั้นสุดท้ายเพื่อรองรับเบราว์เซอร์หลัก ๆ ทั้งหมด
หากคุณใช้ lodash สามารถทำได้อย่างรัดกุมด้วย fromPairs
import {fromPairs} from 'lodash';
const object = fromPairs(Array.from(formData.entries()));
คุณสามารถลองสิ่งนี้
formDataToJSON($('#form_example'));
# Create a function to convert the serialize and convert the form data
# to JSON
# @param : $('#form_example');
# @return a JSON Stringify
function formDataToJSON(form) {
let obj = {};
let formData = form.serialize();
let formArray = formData.split("&");
for (inputData of formArray){
let dataTmp = inputData.split('=');
obj[dataTmp[0]] = dataTmp[1];
}
return JSON.stringify(obj);
}
แม้ว่าคำตอบจาก @dzuc จะดีมากอยู่แล้ว แต่คุณสามารถใช้การทำลายโครงสร้างอาร์เรย์ (มีในเบราว์เซอร์สมัยใหม่หรือกับ Babel) เพื่อให้ดูหรูหราขึ้นอีกเล็กน้อย:
// original version from @dzuc
const data = Array.from(formData.entries())
.reduce((memo, pair) => ({
...memo,
[pair[0]: pair[1],
}), {})
// with array destructuring
const data = Array.from(formData.entries())
.reduce((memo,[key, value]) => ({
...memo,
[key]: value,
}), {})
ซับเดียวที่ไม่เหมาะสม!
Array.from(fd).reduce((obj, [k, v]) => ({...obj, [k]: v}), {});
วันนี้ฉันได้เรียนรู้ว่า Firefox มีการรองรับการแพร่กระจายวัตถุและการทำลายโครงสร้างอาร์เรย์!
หากรายการต่อไปนี้ตรงกับความต้องการของคุณคุณก็โชคดี:
[['key','value1'], ['key2','value2']
(เช่นเดียวกับที่ FormData ให้คุณ) เป็นคีย์ -> ออบเจ็กต์ค่าเช่น{key1: 'value1', key2: 'value2'}
และแปลงเป็นสตริง JSONนี่คือรหัสที่คุณต้องการ:
const data = new FormData(document.querySelector('form'));
const json = JSON.stringify(Array.from(data).reduce((o,[k,v])=>(o[k]=v,o),{}));
หวังว่านี่จะช่วยใครบางคนได้
ฉันไม่เห็นการกล่าวถึงวิธีFormData.getAllเลย
นอกเหนือจากการส่งคืนค่าทั้งหมดที่เกี่ยวข้องกับคีย์ที่กำหนดจากภายในออบเจ็กต์ FormData แล้วมันยังง่ายมากโดยใช้เมธอดObject.fromEntriesตามที่ระบุโดยผู้อื่นที่นี่
var formData = new FormData(document.forms[0])
var obj = Object.fromEntries(
Array.from(formData.keys()).map(key => [
key, formData.getAll(key).length > 1 ?
formData.getAll(key) : formData.get(key)
])
)
Snippet ในการดำเนินการ
var formData = new FormData(document.forms[0])
var obj = Object.fromEntries(Array.from(formData.keys()).map(key => [key, formData.getAll(key).length > 1 ? formData.getAll(key) : formData.get(key)]))
document.write(`<pre>${JSON.stringify(obj)}</pre>`)
<form action="#">
<input name="name" value="Robinson" />
<input name="items" value="Vin" />
<input name="items" value="Fromage" />
<select name="animals" multiple id="animals">
<option value="tiger" selected>Tigre</option>
<option value="turtle" selected>Tortue</option>
<option value="monkey">Singe</option>
</select>
</form>
ฉันคิดว่านี่เป็นวิธีที่ง่ายที่สุดในการรับผลลัพธ์ที่คุณต้องการจากformData
วัตถุ FormData:
const jsonData = {};
for(const [key, value] of formData) {
jsonData[key] = value;
}
ทำงานให้ฉัน
var myForm = document.getElementById("form");
var formData = new FormData(myForm),
obj = {};
for (var entry of formData.entries()){
obj[entry[0]] = entry[1];
}
console.log(obj);
<select multiple>
หรือ<input type="checkbox">
ในรูปแบบกรณีของฉันข้อมูลคือข้อมูลฐานไฟคาดหวังว่าจะมีวัตถุ แต่ข้อมูลมีวัตถุเช่นเดียวกับสิ่งอื่น ๆ ทั้งหมดดังนั้นฉันจึงลองใช้ data ค่ามันใช้งานได้ !!!
ฉันมาถึงที่นี่ช้า อย่างไรก็ตามฉันได้สร้างวิธีง่ายๆที่ตรวจสอบประเภทอินพุต = "ช่องทำเครื่องหมาย"
var formData = new FormData($form.get(0));
var objectData = {};
formData.forEach(function (value, key) {
var updatedValue = value;
if ($('input[name="' + key + '"]').attr("type") === "checkbox" && $('input[name="' + key + '"]').is(":checked")) {
updatedValue = true; // we don't set false due to it is by default on HTML
}
objectData[key] = updatedValue;
});
var jsonData = JSON.stringify(objectData);
ฉันหวังว่านี่จะช่วยคนอื่นได้
JSON.stringify()
ช่วย? บางทีคุณอาจพยายามแก้ไขบางสิ่งที่อาจทำได้ด้วยวิธีอื่น?