แบบฟอร์ม javascript แบบอนุกรม (ไม่มีกรอบ)


148

สงสัยว่ามีฟังก์ชั่นใน javascript ที่ไม่มี jquery หรือเฟรมเวิร์กใด ๆ ที่อนุญาตให้ฉันจัดรูปแบบและเข้าถึงเวอร์ชันซีเรียล


1
"เข้าถึงเวอร์ชันซีเรียลไลซ์" หมายความว่าอย่างไร ฉันได้พัฒนาสคริปต์ที่ไม่มีการอ้างอิงของบุคคลที่สามที่สามารถแปลงรูปแบบ HTML เป็น JSON เช่นวัตถุซึ่งมีหลายมิติ: github.com/serbanghita/formToObject - หากช่วยตอบกลับ
Șerban Ghiță

คำตอบ:


41

ไลบรารีขนาดเล็กจากซีเรียลไลซ์ไม่ขึ้นอยู่กับเฟรมเวิร์ก นอกเหนือจากนั้นคุณจะต้องใช้ฟังก์ชันการทำให้เป็นอนุกรมด้วยตัวเอง (แม้ว่าน้ำหนัก 1.2 กิโลไบต์ทำไมไม่ใช้ล่ะ?)


2
มันสมบูรณ์แบบ แต่ต้องเพิ่มcase 'email':ในส่วนอินพุตของรหัส
aravind

ตอนนี้ฉันเห็นแล้วว่า googlecode ใช้งานไม่ได้หากไม่มีจาวาสคริปต์ มันแค่ถ่มน้ำลายThat's an error
user1040495

3
โปรดใส่รหัสไม่ใช่แค่ลิงก์ไปยังห้องสมุด หากไลบรารีเป็นโอเพ่นซอร์สคุณควรคัดลอกโค้ดที่เกี่ยวข้องได้
ลุค

180

นี่คือแนวทาง JavaScript ที่แท้จริง:

var form = document.querySelector('form');
var data = new FormData(form);
var req = new XMLHttpRequest();
req.send(data);

แม้ว่าดูเหมือนว่าจะใช้ได้กับคำขอ POST เท่านั้น

https://developer.mozilla.org/en-US/docs/Web/API/FormData


14
หมายเหตุสิ่งนี้จะส่งหลายส่วนซึ่งทำงานได้ไม่ดีกับบริการ REST ที่เรียบง่ายบางอย่าง (เช่น Feather-mongoDB)
Jason McCarrell

ฉันคิดว่าคุณคิดถูกแล้วที่ใช้ได้กับคำขอ POST เท่านั้น นั่นยังไม่ชัดเจนในทันทีจากเอกสาร
manisha

สิ่งนี้ไม่ได้ผลสำหรับฉัน แบบฟอร์มฝังลึก วัตถุ FormData ว่างเปล่า…
chitzui

หมายเหตุคุณอาจต้องใช้req.open("POST", "<your-url>");ก่อนreq.send(data);มิฉะนั้นฉันมีข้อผิดพลาดInvalidStateError: XMLHttpRequest state must be OPENED.ใน Firefox 66 ควรทำงานร่วมกับคำขออื่น ๆ เช่น PUT คือคุณแทนที่ POST ด้วย PUT
baptx

1
ลองคิดดู: คุณจะส่งวัตถุ FormData โดยใช้เมธอด "GET" ได้อย่างไร? ใช่ FormData ใช้ได้กับ "POST" เท่านั้น
Rex the Strange

96

สำหรับเบราว์เซอร์สมัยใหม่เท่านั้น

หากคุณกำหนดเป้าหมายเบราว์เซอร์ที่รองรับURLSearchParamsAPI ( เบราว์เซอร์ล่าสุด ) และตัวFormData(formElement)สร้าง ( เบราว์เซอร์ล่าสุด ) ให้ใช้สิ่งนี้:

new URLSearchParams(new FormData(formElement)).toString()

ทุกที่ยกเว้น IE

สำหรับเบราว์เซอร์ที่รองรับURLSearchParamsแต่ไม่ใช่ตัวFormData(formElement)สร้างให้ใช้FormData polyfillนี้และรหัสนี้ (ใช้ได้ทุกที่ยกเว้น IE):

new URLSearchParams(Array.from(new FormData(formElement))).toString()

ตัวอย่าง

เข้ากันได้กับ IE 10

สำหรับเบราว์เซอร์รุ่นเก่า (เช่น IE 10) ให้ใช้FormData polyfillซึ่งเป็นArray.frompolyfill หากจำเป็นและรหัสนี้:

Array.from(
  new FormData(formElement),
  e => e.map(encodeURIComponent).join('=')
).join('&')

ที่นี่.toString()จำเป็นจริงๆหรือ?
Ollie Williams

1
ถ้าคุณต้องการสตริงไม่ใช่URLSearchParamsใช่ การแปลงสตริงยังเกิดขึ้นโดยปริยายหากคุณแก้ไขหรือเพิ่มลงในสตริงซึ่งในกรณีtoStringนี้ไม่จำเป็นต้องมีการเรียกที่ชัดเจน
glebm

One-liner ใช้งานไม่ได้สำหรับฉันบน iOS Safari ณ เดือนเมษายน 2018
jchook

คุณได้รับข้อผิดพลาดอะไรและ Safari เป็นเวอร์ชันใด อาจnew FormData(formElement)จะยังไม่รองรับ?
glebm

@glebm ใช่มันไม่รองรับใน Safari คุณพบวิธีแก้ปัญหาอื่นหรือไม่?
rishiAgar

34
function serialize (form) {
    if (!form || form.nodeName !== "FORM") {
            return;
    }
    var i, j, q = [];
    for (i = form.elements.length - 1; i >= 0; i = i - 1) {
        if (form.elements[i].name === "") {
            continue;
        }
        switch (form.elements[i].nodeName) {
            case 'INPUT':
                switch (form.elements[i].type) {
                    case 'text':
                    case 'tel':
                    case 'email':
                    case 'hidden':
                    case 'password':
                    case 'button':
                    case 'reset':
                    case 'submit':
                        q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
                        break;
                    case 'checkbox':
                    case 'radio':
                        if (form.elements[i].checked) {
                                q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
                        }                                               
                        break;
                }
                break;
                case 'file':
                break; 
            case 'TEXTAREA':
                    q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
                    break;
            case 'SELECT':
                switch (form.elements[i].type) {
                    case 'select-one':
                        q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
                        break;
                    case 'select-multiple':
                        for (j = form.elements[i].options.length - 1; j >= 0; j = j - 1) {
                            if (form.elements[i].options[j].selected) {
                                    q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].options[j].value));
                            }
                        }
                        break;
                }
                break;
            case 'BUTTON':
                switch (form.elements[i].type) {
                    case 'reset':
                    case 'submit':
                    case 'button':
                        q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
                        break;
                }
                break;
            }
        }
    return q.join("&");
}

ที่มา: http://code.google.com/p/form-serialize/source/browse/trunk/serialize-0.1.js


1
การทำให้เป็นอนุกรมนั้นไม่เข้ากันได้กับการทำให้เป็นอนุกรมในรูปแบบมาตรฐานโดยที่ช่องว่างจะแสดงด้วย "+" ข้างต้นใช้เฉพาะencodeURIComponentซึ่งจะเข้ารหัสพื้นที่เป็น "% 20" หากต้องการความสอดคล้องสามารถใช้นิพจน์ทั่วไปในตอนท้ายเพื่อแปลง "% 20" เป็น "+" ก่อนที่จะส่ง
RobG

3
ฉันได้เพิ่มเวอร์ชันแก้ไขดังกล่าวในgist.github.com/brettz9/7147458 (พร้อมการปรับปรุงอื่น ๆ )
Brett Zamir

3
ไม่จำเป็นต้องส่งปุ่มส่งไม่ควรส่งปุ่มรีเซ็ตและปุ่มที่ใช้ในการส่งเท่านั้นและจะถือว่าเป็นปุ่มส่งในกรณีนั้น ดูHTML5 ส่ง
RobG

อย่าจัดลำดับอีเมลประเภทอินพุต
Ivan

25

นี่คือ TibTibs เวอร์ชันแก้ไขเล็กน้อย:

function serialize(form) {
    var field, s = [];
    if (typeof form == 'object' && form.nodeName == "FORM") {
        var len = form.elements.length;
        for (i=0; i<len; i++) {
            field = form.elements[i];
            if (field.name && !field.disabled && field.type != 'file' && field.type != 'reset' && field.type != 'submit' && field.type != 'button') {
                if (field.type == 'select-multiple') {
                    for (j=form.elements[i].options.length-1; j>=0; j--) {
                        if(field.options[j].selected)
                            s[s.length] = encodeURIComponent(field.name) + "=" + encodeURIComponent(field.options[j].value);
                    }
                } else if ((field.type != 'checkbox' && field.type != 'radio') || field.checked) {
                    s[s.length] = encodeURIComponent(field.name) + "=" + encodeURIComponent(field.value);
                }
            }
        }
    }
    return s.join('&').replace(/%20/g, '+');
}

ช่องที่ปิดใช้งานจะถูกละทิ้งและมีการเข้ารหัส URL ด้วย การแทนที่ Regex ของอักขระ% 20 จะเกิดขึ้นเพียงครั้งเดียวก่อนที่จะส่งคืนสตริง

สตริงแบบสอบถามอยู่ในรูปแบบที่เหมือนกันกับผลลัพธ์จากวิธี $ .serialize () ของ jQuery


6
+1 ที่สละเวลาปรับปรุงโค้ด ฉันสนุกเมื่อมีคนพบข้อบกพร่องของฉันเพราะมันเป็นโอกาสในการเรียนรู้ที่ดี +1 เพื่อให้ดูดีเช่นกัน -1 เพราะฉันไม่สามารถให้ +2 = (
TibTibs

1
คุณสามารถเพิ่มform.nodeName.toLowerCase() == "form"แทนform.nodeName == "FORM"
StefanNch

12

ฉันเริ่มต้นด้วยคำตอบจาก Johndave Decano

สิ่งนี้ควรแก้ไขปัญหาบางประการที่กล่าวถึงในการตอบกลับฟังก์ชันของเขา

  1. แทนที่% 20 ด้วยสัญลักษณ์ +
  2. ประเภทส่ง / ปุ่มจะถูกส่งก็ต่อเมื่อมีการคลิกเพื่อส่งแบบฟอร์ม
  3. ปุ่มรีเซ็ตจะถูกละเว้น
  4. รหัสดูเหมือนซ้ำซ้อนสำหรับฉันเนื่องจากมันทำสิ่งเดียวกันโดยไม่คำนึงถึงประเภทฟิลด์ ไม่ต้องพูดถึงความเข้ากันไม่ได้กับประเภทฟิลด์ HTML5 เช่น 'tel' และ 'email' ดังนั้นฉันจึงลบข้อมูลเฉพาะส่วนใหญ่ออกด้วยคำสั่ง switch

ประเภทปุ่มจะยังคงถูกละเว้นหากไม่มีค่าชื่อ

function serialize(form, evt){
    var evt    = evt || window.event;
    evt.target = evt.target || evt.srcElement || null;
    var field, query='';
    if(typeof form == 'object' && form.nodeName == "FORM"){
        for(i=form.elements.length-1; i>=0; i--){
            field = form.elements[i];
            if(field.name && field.type != 'file' && field.type != 'reset'){
                if(field.type == 'select-multiple'){
                    for(j=form.elements[i].options.length-1; j>=0; j--){
                        if(field.options[j].selected){
                            query += '&' + field.name + "=" + encodeURIComponent(field.options[j].value).replace(/%20/g,'+');
                        }
                    }
                }
                else{
                    if((field.type != 'submit' && field.type != 'button') || evt.target == field){
                        if((field.type != 'checkbox' && field.type != 'radio') || field.checked){
                            query += '&' + field.name + "=" + encodeURIComponent(field.value).replace(/%20/g,'+');
                        }   
                    }
                }
            }
        }
    }
    return query.substr(1);
}

นี่คือวิธีที่ฉันกำลังใช้ฟังก์ชันนี้

<form onsubmit="myAjax('http://example.com/services/email.php', 'POST', serialize(this, event))">

6
+1 สำหรับโค้ด refactored อย่างดี -1 สำหรับการไม่สนใจฟิลด์ที่ปิดใช้งานซึ่งไม่ควรปรากฏในสตริงการสืบค้น +1 สำหรับคำสั่งที่หรูหรามากซึ่งหลีกเลี่ยงการนับองค์ประกอบแบบฟอร์มซ้ำ ๆ ทั้งหมด: +1 :-) ขอบคุณ!
Simon Steinberger

ทราบดีเกี่ยวกับฟิลด์ที่ปิดใช้งานฉันพบเมื่อเร็ว ๆ นี้พร้อมกับฟังก์ชันใหม่ที่ฉันกำลังเขียน +1 ให้คุณทั้งสองคนเพราะฉันชอบอ่านความคิดเห็นสนุก ๆ :)
TibTibs

12

หากคุณต้องการส่งแบบฟอร์ม "myForm" โดยใช้ POST ในรูปแบบ json คุณสามารถทำได้:

const formEntries = new FormData(myForm).entries();
const json = Object.assign(...Array.from(formEntries, ([x,y]) => ({[x]:y})));
fetch('/api/foo', {
  method: 'POST',
  body: JSON.stringify(json)
});

บรรทัดที่สองแปลงจากอาร์เรย์เช่น:

[["firstProp", "firstValue"], ["secondProp", "secondValue"], ...and so on... ]

... ลงในวัตถุปกติเช่น:

{"firstProp": "firstValue", "secondProp": "secondValue", ...and so on ... }

... มันทำการแปลงโดยส่ง mapFn ไปยัง Array.from () mapFn นี้ใช้กับ ["a", "b"] แต่ละคู่และแปลงเป็น {"a": "b"} เพื่อให้อาร์เรย์มีออบเจ็กต์จำนวนมากที่มีคุณสมบัติเพียงหนึ่งรายการในแต่ละคู่ mapFn ใช้ "การทำลายโครงสร้าง" เพื่อรับชื่อของส่วนแรกและส่วนที่สองของคู่และยังใช้ ES6 "ComputedPropertyName" เพื่อตั้งชื่อคุณสมบัติในวัตถุที่ mapFn ส่งคืน (นี่คือเหตุผลที่ระบุว่า "[ x]: บางสิ่งบางอย่าง "แทนที่จะเป็นเพียง" x: something "

จากนั้นอ็อบเจ็กต์คุณสมบัติเดี่ยวทั้งหมดเหล่านี้จะถูกส่งผ่านไปยังอาร์กิวเมนต์ของฟังก์ชัน Object.assign () ซึ่งรวมอ็อบเจ็กต์คุณสมบัติเดียวทั้งหมดเข้าเป็นอ็อบเจ็กต์เดียวที่มีคุณสมบัติทั้งหมด

Array.from (): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from

การทำลายโครงสร้างในพารามิเตอร์: https://simonsmith.io/destructuring-objects-as-function-parameters-in-es6/

เพิ่มเติมเกี่ยวกับชื่อคุณสมบัติที่คำนวณได้ที่นี่: Variable as the property name in a JavaScript object literal?


มันใช้ได้สำหรับฉันแม้ว่าฉันจะไม่เข้าใจบรรทัดที่สองคุณสามารถให้ข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ได้หรือไม่?
Espoir Murhabazi

คำตอบที่สวยงามโดยใช้ตัวดำเนินการกระจายและวิธีการ Object และ Array ดั้งเดิม
Vinny Fonseca

โปรดทราบว่าวิธีนี้ไม่รองรับใน IE (.entries ())
dude

หน้า MDN สำหรับ Object.entries () มี polyfill สั้น ๆ ที่คุณสามารถใช้สำหรับ IE: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…แต่ IE ยังไม่รองรับตัวดำเนินการแพร่กระจาย
molsson

1
คุณสามารถจัดลำดับฟอร์มโดยใช้วิธีการใหม่ Object.fromEntries (FormData ใหม่ (myFormElement))
miguel savignano

9

ใช้ได้กับทุกเบราว์เซอร์

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>


สิ่งนี้ทำให้ json ฉันถือว่าผู้เขียนกำลังถามเกี่ยวกับการทำให้เป็นอนุกรมกับ URI
jaskmar

ฉันชอบที่จะเห็นสิ่งนี้ใช้ได้กับแบบฟอร์มตัวเลือกที่หลากหลาย
Zach Smith

@ZachSmith มันใช้งานได้แล้ว แต่ฉันเพิ่มตัวอย่างให้คุณตรวจสอบ
David Lemon

8
HTMLElement.prototype.serialize = function(){
    var obj = {};
    var elements = this.querySelectorAll( "input, select, textarea" );
    for( var i = 0; i < elements.length; ++i ) {
        var element = elements[i];
        var name = element.name;
        var value = element.value;

        if( name ) {
            obj[ name ] = value;
        }
    }
    return JSON.stringify( obj );
}

วิธีใช้ดังนี้:

var dataToSend = document.querySelector("form").serialize();

ฉันหวังว่าฉันจะได้ช่วย


3
จะไม่ทำงานกับช่องทำเครื่องหมาย ที่นี่คุณต้องตรวจสอบประเภทอินพุตอย่างชัดเจน
Adrian Preuss

5

หากคุณต้องการจัดลำดับอินพุตในเหตุการณ์ นี่เป็นวิธี JavaScript ที่แท้จริงที่ฉันใช้

// serialize form
var data = {};
var inputs = [].slice.call(e.target.getElementsByTagName('input'));
inputs.forEach(input => {
  data[input.name] = input.value;
});

ข้อมูลจะเป็นวัตถุ JavaScript ของอินพุต


2
สิ่งนี้ควรใช้ได้กับองค์ประกอบส่วนใหญ่ ไม่ใช่ textarea / select อย่างแน่นอน
jaggedsoft

slice.call นั้นเหมือนกับ Array.from หรือไม่
user1040495

5

โค้ดของ @ SimonSteinberger รุ่น refactored โดยใช้ตัวแปรน้อยกว่าและใช้ประโยชน์จากความเร็วของforEachลูป (ซึ่งเร็วกว่าfors เล็กน้อย)

function serialize(form) {
    var result = [];
    if (typeof form === 'object' && form.nodeName === 'FORM')
        Array.prototype.slice.call(form.elements).forEach(function(control) {
            if (
                control.name && 
                !control.disabled && 
                ['file', 'reset', 'submit', 'button'].indexOf(control.type) === -1
            )
                if (control.type === 'select-multiple')
                    Array.prototype.slice.call(control.options).forEach(function(option) {
                        if (option.selected) 
                            result.push(encodeURIComponent(control.name) + '=' + encodeURIComponent(option.value));
                    });
                else if (
                    ['checkbox', 'radio'].indexOf(control.type) === -1 || 
                    control.checked
                ) result.push(encodeURIComponent(control.name) + '=' + encodeURIComponent(control.value));
        });
        return result.join('&').replace(/%20/g, '+');
}

3

ฉันปรับโครงสร้างคำตอบของ TibTibs เป็นสิ่งที่อ่านได้ชัดเจนกว่ามาก มันยาวขึ้นเล็กน้อยเนื่องจากความกว้าง 80 อักขระและความคิดเห็นเล็กน้อย

นอกจากนี้ยังละเว้นชื่อฟิลด์ว่างและค่าว่าง

// Serialize the specified form into a query string.
//
// Returns a blank string if +form+ is not actually a form element.
function $serialize(form, evt) {
  if(typeof(form) !== 'object' && form.nodeName !== "FORM")
    return '';

  var evt    = evt || window.event || { target: null };
  evt.target = evt.target || evt.srcElement || null;
  var field, query = '';

  // Transform a form field into a query-string-friendly
  // serialized form.
  //
  // [NOTE]: Replaces blank spaces from its standard '%20' representation
  //         into the non-standard (though widely used) '+'.
  var encode = function(field, name) {
    if (field.disabled) return '';

    return '&' + (name || field.name) + '=' +
           encodeURIComponent(field.value).replace(/%20/g,'+');
  }

  // Fields without names can't be serialized.
  var hasName = function(el) {
    return (el.name && el.name.length > 0)
  }

  // Ignore the usual suspects: file inputs, reset buttons,
  // buttons that did not submit the form and unchecked
  // radio buttons and checkboxes.
  var ignorableField = function(el, evt) {
    return ((el.type == 'file' || el.type == 'reset')
        || ((el.type == 'submit' || el.type == 'button') && evt.target != el)
        || ((el.type == 'checkbox' || el.type == 'radio') && !el.checked))
  }

  var parseMultiSelect = function(field) {
    var q = '';

    for (var j=field.options.length-1; j>=0; j--) {
      if (field.options[j].selected) {
        q += encode(field.options[j], field.name);
      }
    }

    return q;
  };

  for(i = form.elements.length - 1; i >= 0; i--) {
    field = form.elements[i];

    if (!hasName(field) || field.value == '' || ignorableField(field, evt))
      continue;

    query += (field.type == 'select-multiple') ? parseMultiSelect(field)
                                               : encode(field);
  }

  return (query.length == 0) ? '' : query.substr(1);
}

ฉันคัดลอกสิ่งนี้ลงในแอปของฉันโดยตรงและการเลือกหลายรายการไม่ทำงาน (ค่าซ้ำกัน)
ผิดปกติ

@anastymous ขอบคุณสำหรับการจับมันได้รับการแก้ไขแล้ว
Brian Edmonds

สวัสดี Brian evt มีไว้เพื่ออะไร? และฉันควรจะผ่านมันไปเพื่ออะไร? Firefox กำลังบอกฉันว่ามันไม่ได้กำหนดไว้
anastymous

สวัสดี anastymous ขอบคุณอีกครั้งสำหรับการจับควรได้รับการแก้ไขโดยการเปลี่ยนการกำหนดเป็น evt เป็น evt = evt || window.event || { target: null };(ตามที่การแก้ไขเสร็จสิ้น) จุดที่อยู่เบื้องหลังคือการส่งผ่านเหตุการณ์ที่ทำให้เกิดการทำให้เป็นอนุกรมหากมีเช่นแบบฟอร์ม "ส่ง" เหตุการณ์หรือ "คลิก" ของปุ่ม หากแบบฟอร์มมีปุ่มหลายปุ่มสำหรับการส่งคุณต้องการพิจารณาเฉพาะค่าของปุ่มที่ทำให้เกิดเหตุการณ์และไม่สนใจปุ่มอื่น ๆ ฉันได้แฮ็กตัวอย่างพื้นฐานของพฤติกรรมนี้ในdump.bedmonds.net/serialize-js
Brian Edmonds

3

ซึ่งสามารถทำได้โดยใช้ฟังก์ชันง่ายๆดังนี้

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>


2
  // 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);

2

ฉันได้รับรายการ () วิธีการของ formData จากคำตอบ @moison และจากMDNมีการกล่าวว่า:

FormData.entries () วิธีการส่งคืนตัววนซ้ำที่อนุญาตให้ผ่านคู่คีย์ / ค่าทั้งหมดที่มีอยู่ในวัตถุนี้ คีย์ของแต่ละคู่คือวัตถุ USVString ค่า USVString หรือ Blob

แต่ปัญหาเดียวคือเบราว์เซอร์มือถือ (ไม่รองรับ Android และ Safari) และ IE และเดสก์ท็อป Safari ด้วย

แต่โดยพื้นฐานแล้วนี่คือแนวทางของฉัน:

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'

};

รหัสสามารถพบได้ที่นี่


2

การใช้ฟังก์ชันลด JavaScript ควรใช้เคล็ดลับสำหรับเบราว์เซอร์ทั้งหมดรวมถึง 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;
 },[]);

ร้องตัวอย่างสด


สิ่งนี้ใช้ได้กับการเลือกหลายรายการหรือไม่ ดูเหมือนว่าเมื่อฉันใช้รหัสของคุณมันจะส่งกลับรายการแรกของค่าตัวเลือกที่เลือกหลายรายการเท่านั้น
Zach Smith

@ZachSmith ฉันได้อัปเดตคำตอบของฉันเพื่อรวมองค์ประกอบที่เลือกหลายรายการ
crashtestxxx

1

ปรับปรุงตามคำตอบของ David Lemon

สิ่งนี้จะแปลงข้อมูลฟอร์มเป็น JSON และช่วยให้คุณตั้งค่าฟอร์มจากออบเจ็กต์ข้อมูล

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>


1

นี่คือแนวทาง JavaScript ที่แท้จริง:

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);
}

0

ฉันหวังว่านี่จะได้ผล

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;
}

-1
document.serializeForm = function (selector) {
     var dictionary = {};
     var form = document.querySelector(selector);
     var formdata = new FormData(form);
     var done = false;
     var iterator = formdata.entries();
     do {
         var prop = iterator.next();
         if (prop.done && !prop.value) {
             done = true;
         }
         else {
             dictionary[prop.value[0]] = prop.value[1];
         }

     } while (!done);
     return dictionary;
}

ดูเรียบร้อย แต่ไม่คำนึงถึงปุ่มตัวเลือกหรือช่องทำเครื่องหมาย
Yvonne Aburrow

-1

สำหรับวัตถุประสงค์ในการดีบักสิ่งนี้อาจช่วยคุณได้:

function print_form_data(form) {
    const form_data = new FormData(form);

    for (const item of form_data.entries()) {
        console.log(item);
    }

    return false;
}

-1

ฉันอาจจะบ้า แต่ฉันพบคำตอบเหล่านี้ป่อง นี่คือทางออกของฉัน

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);
}

การใช้แบบฟอร์มของคุณเพื่อดึงองค์ประกอบตามประเภทอินพุตจะล้มเหลวสำหรับselectและอื่น ๆ
Zach Smith
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.