Konversi data formulir ke objek JavaScript dengan jQuery

1624

Bagaimana cara mengonversi semua elemen formulir saya ke objek JavaScript?

Saya ingin memiliki beberapa cara untuk secara otomatis membangun objek JavaScript dari formulir saya, tanpa harus mengulang setiap elemen. Saya tidak ingin string, seperti yang dikembalikan oleh $('#formid').serialize();, saya juga tidak ingin peta dikembalikan oleh$('#formid').serializeArray();

Yisroel
sumber
16
karena yang pertama mengembalikan string, persis seperti apa yang akan Anda dapatkan jika Anda mengirimkan formulir dengan metode GET, dan yang kedua memberi Anda array objek, masing-masing dengan pasangan nilai nama. Saya ingin bahwa jika saya memiliki bidang bernama "email" saya mendapatkan objek yang akan memungkinkan saya untuk mengambil nilai itu dengan obj.email. Dengan serializeArray (), saya harus melakukan sesuatu seperti obj [indexOfElement] .value
Yisroel
2
@ James - Jawaban yang diterima menggunakan pustaka JSON-js D. Crockford. Berikut ini contohnya: github.com/tleese22/google-app-engine-jappstart/blob/master/src/…
Taylor Leese
4
@ Taylor Ya, saya akan mengatakan jawaban yang benar menggunakan fungsi Crockford lib dan Tobias seperti: JSON.stringify ($ ('myForm'). SerializeObject ())
James McCormack
5
@ Jonz - Ada alasan lain selain pengiriman / transmisi untuk menggunakan elemen formulir. Jika Anda melakukan pengangkatan berat dengan nilai formulir dalam JavaScript (mis. Aplikasi satu halaman), sangat berguna untuk membuatnya dalam format objek untuk diakses & dimanipulasi. Juga, HTTP Post dan Get strings query bukan satu-satunya format untuk memindahkan data.
Patrick M
3
Js baik saya temui >> github.com/marioizquierdo/jquery.serializeJSON
Bongs

Jawaban:

1657

serializeArraysudah melakukan hal itu. Anda hanya perlu memijat data ke dalam format yang Anda butuhkan:

function objectifyForm(formArray) {//serialize data function

  var returnArray = {};
  for (var i = 0; i < formArray.length; i++){
    returnArray[formArray[i]['name']] = formArray[i]['value'];
  }
  return returnArray;
}

Perhatikan bidang tersembunyi yang memiliki nama yang sama dengan input asli karena akan ditimpa.

Tobias Cohen
sumber
4
seperti yang dikatakan tvanfosson, mengapa harus mengulang koleksi dua kali?
Yisroel
69
Apakah maksud Anda "mengapa menggunakan serializeArray untuk mendapatkan data di tempat pertama?" Karena serializeArray sudah ditulis, unit diuji dalam beberapa browser, dan secara teoritis dapat ditingkatkan di versi jQuery yang lebih baru. Semakin sedikit kode yang Anda tulis yang harus mengakses hal-hal yang tidak konsisten seperti elemen DOM secara langsung, semakin stabil kode Anda.
Tobias Cohen
56
Berhati-hatilah, serializeArray () tidak akan menyertakan elemen yang dinonaktifkan. Saya sering menonaktifkan elemen input yang disinkronkan ke elemen lain di halaman, tetapi saya masih ingin mereka dimasukkan ke dalam objek serial saya. Anda lebih baik menggunakan sesuatu seperti $.map( $("#container :input"), function(n, i) { /* n.name and $(n).val() */ } );jika Anda perlu memasukkan elemen yang dinonaktifkan.
Samuel Meacham
22
@TobiasCohen Ini tidak menangani foo[bar]input -tipe seperti yang diharapkan, belum lagi sebagian besar varietas nama input lainnya. Setelah sangat frustrasi dengan solusi dangkal untuk masalah ini, saya akhirnya menulis plugin jQuery saya sendiri - detail dalam jawaban yang saya berikan untuk pertanyaan ini.
maček
6
@ Macek Saya tahu ini berumur beberapa bulan, tetapi sejak kapan array menggunakan indeks non-numerik? Tidak seorang pun boleh menyebutkan nama input foo [bar] dan berharap untuk memperlakukannya sebagai array. Apakah Anda membingungkan array dan hash? Ya, [] umumnya dipahami sebagai accessor tetapi tidak hanya untuk array. Juga mengatakan itu HTML yang valid tetapi tidak dalam spesifikasi HTML adalah kontradiksi. Ya, peramban mungkin tidak mencekiknya, tetapi tidak banyak webserver yang tahu cara deserialisasi seperti mereka menggunakan array. Mengapa? Karena tidak ada dalam spesifikasi HTML. Karena itu, memang tidak valid.
kroehre
446

Konversikan formulir ke JSON seperti bos


Sumber saat ini ada di GitHub dan Bower .

$ bower instal jquery-serialize-object


Kode berikut sekarang sudah tidak digunakan lagi .

Kode berikut dapat bekerja dengan semua jenis nama input; dan menanganinya seperti yang Anda harapkan.

Sebagai contoh:

<!-- All of these will work! -->
<input name="honey[badger]" value="a">
<input name="wombat[]" value="b">
<input name="hello[panda][]" value="c">
<input name="animals[0][name]" value="d">
<input name="animals[0][breed]" value="e">
<input name="crazy[1][][wonky]" value="f">
<input name="dream[as][vividly][as][you][can]" value="g">
// Output
{
  "honey":{
    "badger":"a"
  },
  "wombat":["b"],
  "hello":{
    "panda":["c"]
  },
  "animals":[
    {
      "name":"d",
      "breed":"e"
    }
  ],
  "crazy":[
    null,
    [
      {"wonky":"f"}
    ]
  ],
  "dream":{
    "as":{
      "vividly":{
        "as":{
          "you":{
            "can":"g"
          }
        }
      }
    }
  }
}

Pemakaian

$('#my-form').serializeObject();

The Sorcery (JavaScript)

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

        var self = this,
            json = {},
            push_counters = {},
            patterns = {
                "validate": /^[a-zA-Z][a-zA-Z0-9_]*(?:\[(?:\d*|[a-zA-Z0-9_]+)\])*$/,
                "key":      /[a-zA-Z0-9_]+|(?=\[\])/g,
                "push":     /^$/,
                "fixed":    /^\d+$/,
                "named":    /^[a-zA-Z0-9_]+$/
            };


        this.build = function(base, key, value){
            base[key] = value;
            return base;
        };

        this.push_counter = function(key){
            if(push_counters[key] === undefined){
                push_counters[key] = 0;
            }
            return push_counters[key]++;
        };

        $.each($(this).serializeArray(), function(){

            // Skip invalid keys
            if(!patterns.validate.test(this.name)){
                return;
            }

            var k,
                keys = this.name.match(patterns.key),
                merge = this.value,
                reverse_key = this.name;

            while((k = keys.pop()) !== undefined){

                // Adjust reverse_key
                reverse_key = reverse_key.replace(new RegExp("\\[" + k + "\\]$"), '');

                // Push
                if(k.match(patterns.push)){
                    merge = self.build([], self.push_counter(reverse_key), merge);
                }

                // Fixed
                else if(k.match(patterns.fixed)){
                    merge = self.build([], k, merge);
                }

                // Named
                else if(k.match(patterns.named)){
                    merge = self.build({}, k, merge);
                }
            }

            json = $.extend(true, json, merge);
        });

        return json;
    };
})(jQuery);
pengguna
sumber
17
Jadi, itu bekerja dengan cukup baik. Tapi itu salah nama: itu tidak mengembalikan JSON, seperti namanya. Sebaliknya, ia mengembalikan objek literal. Juga, penting untuk memeriksa hasOwnProperty, jika array Anda memiliki apa pun yang terlampir pada prototipe mereka, seperti: {number: ["1", "3", indexOf: function () {...}]}
frontendbeauty
5
@frontendbeauty sebenarnya, toJSON adalah persis apa yang dikatakan oleh spec itu harus disebut: developer.mozilla.org/en/JSON#toJSON()_method nama yang salah disayangkan.
Ryan Florence
4
@Marek, saya melakukan tes untuk di sini di jsfiddle . Caranya adalah dengan memberi nama pilih Anda dengan benar. <select name="foo" multiple="multiple">tidak akan berfungsi dalam skenario apa pun. Namun, jika Anda menggunakan [], seperti pada <select name="bar[]" multiple="multiple">, itu akan berfungsi dengan baik :)
maček
3
Ingin menunjukkan bahwa github.com/serbanghita/formToObject adalah metode JavaScript yang serupa (tidak perlu pustaka pihak ke-3) yang melakukan pekerjaan yang sama. Mendukung 'banyak', mengabaikan elemen 'dinonaktifkan'.
Șerban Ghiță
8
Solusi ini harus di atas karena berkaitan dengan masalah kunci bersarang sebagai nama elemen bentuk.
SquareCat
283

Ada apa dengan:

var data = {};
$(".form-selector").serializeArray().map(function(x){data[x.name] = x.value;}); 
mkschreder
sumber
2
@ LayZee - jika tidak ada yang dipilih, mengapa Anda menginginkannya di bagian belakang Anda? jika Anda harus memilih opsi, validasi input sebelum membuat cerita bersambung.
Demensik
21
jika Anda tidak mengembalikan apa pun, mengapa Anda tidak menggunakan saja .eachbukan .map??
azerafati
10
Ini sangat sederhana karena sangat naif ... tidak menangani kotak centang dengan nama yang sama. Setiap kali itu akan menimpa item yang diperiksa sebelum itu. Anda pasti membutuhkan beberapa deteksi tipe input untuk memastikan serialisasi dengan benar.
Joshua F. Rountree
5
Jika Anda menginginkan solusi jQuery murni, Anda dapat menggunakanvar form = {}; $.each($(this).serializeArray(), function (i, field) { form[field.name] = field.value || ""; });
tfmontague
42
$(this).serializeArray().reduce(function(m,o){ m[o.name] = o.value; return m;}, {})
situs
103

Versi tetap dari solusi Tobias Cohen. Yang ini dengan benar menangani nilai-nilai palsu seperti 0dan ''.

jQuery.fn.serializeObject = function() {
  var arrayData, objectData;
  arrayData = this.serializeArray();
  objectData = {};

  $.each(arrayData, function() {
    var value;

    if (this.value != null) {
      value = this.value;
    } else {
      value = '';
    }

    if (objectData[this.name] != null) {
      if (!objectData[this.name].push) {
        objectData[this.name] = [objectData[this.name]];
      }

      objectData[this.name].push(value);
    } else {
      objectData[this.name] = value;
    }
  });

  return objectData;
};

Dan versi CoffeeScript untuk kenyamanan pengkodean Anda:

jQuery.fn.serializeObject = ->
  arrayData = @serializeArray()
  objectData = {}

  $.each arrayData, ->
    if @value?
      value = @value
    else
      value = ''

    if objectData[@name]?
      unless objectData[@name].push
        objectData[@name] = [objectData[@name]]

      objectData[@name].push value
    else
      objectData[@name] = value

  return objectData
Daniel X Moore
sumber
Dalam naskah kopi, yang pertama jika blok dapat disingkat menjadivalue = @value ? ''
nzifnab
Dan jika Anda mencoba membuat serial bentuk Rails, Anda mungkin ingin menghapus elemen root dari kunci yang dihasilkan. Untuk mencapai itu, saya telah menambahkan param baru keyMapdan baris berikut: key = if keyMap? then keyMap(@name) else @name. Sekarang Anda dapat melewati fungsi pemetaan seperti (name) -> name.match(/\[([^\]]+)]/)[1]. Dan kemudian orang akan perlu untuk mengubah semua berikutnya @nameuntuk key, tentu saja
Damir Zekić
@ DamirZekić, jika elemen root postAnda, Anda bisa melakukannya $('form').serializeObject().post. Tidak perlu pemetaan mewah.
maček
@ DamirZekić Apa yang dilakukan baris ini? if (!objectData[this.name].push)??
kittu
@ kittu Memeriksa apakah objectData[this.name]memiliki metode push (kira-kira, apakah ini array). Jika itu adalah array, ia mendorong nilai, jika bukan array, itu mengubahnya menjadi array sehingga beberapa nilai dengan kunci yang sama akan digabungkan ke array.
Daniel X Moore
63

Saya suka menggunakan Array.prototype.reducekarena ini adalah one-liner, dan tidak bergantung pada Underscore.js atau sejenisnya:

$('#formid').serializeArray()
    .reduce(function(a, x) { a[x.name] = x.value; return a; }, {});

Ini mirip dengan jawaban yang digunakan Array.prototype.map, tetapi Anda tidak perlu mengacaukan ruang lingkup Anda dengan variabel objek tambahan. Belanja satu atap.

CATATAN PENTING : Formulir dengan input yang memiliki nameatribut duplikat adalah HTML yang valid, dan sebenarnya merupakan pendekatan umum. Menggunakan salah satu jawaban di utas ini akan tidak sesuai dalam kasus itu (karena kunci objek harus unik).

Ethan Brown
sumber
Ini cukup elegan. Tetapi perlu dicatat bahwa array.prototype.reduce()tidak tersedia di IE8 karena ini adalah bagian dari spesifikasi ECMAScript 5. Jadi jika Anda memerlukan dukungan IE8, Anda ingin menggunakan polyfill atau solusi lain sekaligus.
gfullam
3
Benar, tetapi cukup mudah untuk mengisi polyfill. Selain itu, sakit kepala IE8 hampir berakhir, berkat kerja keras Microsoft dengan IE11 Enterprise Mode - Saya tidak lagi melayani pengguna individu dengan IE8, tetapi ketika sebuah organisasi dengan 10.000 karyawan yang semuanya menggunakan IE8 datang ... itu berbeda. Untungnya, Microsoft bekerja keras untuk masalah itu.
Ethan Brown
1
Nah, Anda harus meminta orang-orang IT Anda untuk melihat ke mode IE11 Enterprise - ini menyediakan browser modern DAN cara untuk menjalankan aplikasi yang kompatibel dengan IE8. Langkah cerdas di pihak Microsoft: howtogeek.com/184634/…
Ethan Brown
30

Semua jawaban ini tampak sangat berlebihan bagi saya. Ada sesuatu yang bisa dikatakan untuk kesederhanaan. Selama semua input formulir Anda memiliki atribut nama yang ditetapkan, ini seharusnya hanya berfungsi.

$('form.myform').submit(function () {
  var $this = $(this)
    , viewArr = $this.serializeArray()
    , view = {};

  for (var i in viewArr) {
    view[viewArr[i].name] = viewArr[i].value;
  }

  //Do stuff with view object here (e.g. JSON.stringify?)
});
Jeffrey Van Alstine
sumber
4
Tidak menangani data formulir bersarang, itu sebabnya jawaban menjadi lebih rumit.
frontendbeauty
Bekerja dengan baik untuk saya. Hanya perlu penyimpanan pasangan nilai kunci; merangkai dan kemudian menyimpan ke localStorage atau cookie bekerja sangat bagus.
Greg Pettit
23

Tidak ada cara untuk melakukan ini tanpa memeriksa setiap elemen. Apa yang benar-benar ingin Anda ketahui adalah "sudahkah orang lain menulis metode yang mengubah formulir menjadi objek JSON?" Sesuatu seperti yang berikut ini seharusnya berfungsi - perhatikan bahwa itu hanya akan memberi Anda elemen bentuk yang akan dikembalikan melalui POST (harus memiliki nama). Ini tidak diuji .

function formToJSON( selector )
{
     var form = {};
     $(selector).find(':input[name]:enabled').each( function() {
         var self = $(this);
         var name = self.attr('name');
         if (form[name]) {
            form[name] = form[name] + ',' + self.val();
         }
         else {
            form[name] = self.val();
         }
     });

     return form;
}
tvanfosson
sumber
benar, saya akan menyukai plugin yang akan melakukan ini untuk saya. keterbatasan memiliki nama bukanlah masalah besar. apakah ini akan menarik semua bidang dalam formulir, termasuk textareas dan seleksi?
Yisroel
tidak yakin apakah Anda ingin akun untuk [dinonaktifkan] tetapi saya tidak berpikir itu harus dikirim / diambil.
meder omuraliev
mungkin lebih mudah untuk menggunakan serializeArray () untuk mendapatkan peta, dan kemudian menggunakan kode yang mirip dengan di atas untuk mengkonversinya menjadi objek JSON normal, dengan cara ini saya tidak berurusan dengan formulir itu sendiri
Yisroel
2
Menggunakan serializedArray akan bekerja, tetapi pada dasarnya Anda akan mengulangi koleksi dua kali - sekali untuk menghasilkan array, kemudian ke array. Saya tidak melihat perlunya untuk itu.
tvanfosson
Saya akan menyesuaikan pemilih untuk diaktifkan / dinonaktifkan.
tvanfosson
23

Jika Anda menggunakan Underscore.js, Anda dapat menggunakan yang relatif ringkas:

_.object(_.map($('#myform').serializeArray(), _.values))
olleicua
sumber
19

Saya memeriksa bahwa ada masalah dengan semua jawaban lainnya, bahwa jika nama input adalah array, seperti name[key], maka harus dihasilkan seperti ini:

name:{ key : value }


Misalnya: Jika Anda memiliki formulir HTML yang mirip dengan yang di bawah ini:

<form>
    <input name="name" value="value" >
    <input name="name1[key1]" value="value1" >
    <input name="name2[key2]" value="value2" >
    <input name="name3[key3]" value="value3" >
</form>

Tetapi harus dihasilkan seperti JSON di bawah ini, dan tidak menjadi objek seperti berikut dengan semua jawaban lainnya. Jadi, jika ada yang ingin membawa sesuatu seperti JSON berikut, coba kode JS di bawah ini.

{
    name  : 'value',
    name1 : { key1 : 'value1' },
    name2 : { key2 : 'value2' },
    name3 : { key2 : 'value2' }
}

$.fn.getForm2obj = function() {
  var _ = {};
  $.map(this.serializeArray(), function(n) {
    const keys = n.name.match(/[a-zA-Z0-9_]+|(?=\[\])/g);
    if (keys.length > 1) {
      let tmp = _;
      pop = keys.pop();
      for (let i = 0; i < keys.length, j = keys[i]; i++) {
        tmp[j] = (!tmp[j] ? (pop == '') ? [] : {} : tmp[j]), tmp = tmp[j];
      }
      if (pop == '') tmp = (!Array.isArray(tmp) ? [] : tmp), tmp.push(n.value);
      else tmp[pop] = n.value;
    } else _[keys.pop()] = n.value;
  });
  return _;
}
console.log($('form').getForm2obj());
$('form input').change(function() {
  console.clear();
  console.log($('form').getForm2obj());
});
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<form>
  <input name="name" value="value">
  <input type="checkbox" name="name1[]" value="1" checked="checked">1
  <input type="checkbox" name="name1[]" value="2">2
  <input type="checkbox" name="name1[]" value="3">3<br>
  <input type="radio" name="gender" value="male" checked="checked">male
  <input type="radio" name="gender" value="female"> female
  <input name="name2[key1]" value="value1">
  <input name="one[another][another_one]" value="value4">
  <input name="name3[1][name]" value="value4">
  <input name="name3[2][name]" value="value4">
  <input name="[]" value="value5">
</form>

Bhavik Hirani
sumber
Jawaban ini tidak mencakup case yang disebutkan, tetapi tidak mencakup case seperti checkbox [] atau bahkan satu [lain] [another_one]
Leonardo Beal
1
@LeonardoBeal saya memperbaiki ans saya .. periksa ini sekarang ..!
Bhavik Hirani
Saya yang downvoter dan saya downvoted karena evaltidak boleh digunakan dengan cara ini karena eval, ketika digunakan dengan cara ini, mempromosikan sangat tidak dapat diandalkan, bermasalah, tidak berperforma baik, dan berpotensi berpotensi praktik tidak aman.
Jack Giffin
2
Saya tidak setuju ini jawaban yang bagus. Dan tolong ketika Anda menulis jawaban, buat kode Anda jelas atau jelaskan. this.c = function(k,v){ eval("c = typeof "+k+";"); if(c == 'undefined') _t.b(k,v);}singkat dan tidak jelas. Seorang pengembang dengan pengalaman yang lebih sedikit hanya akan menyalin ini tanpa memahami mengapa dan cara kerjanya.
iRaS
2
@JackGiffin Periksa kode baru saya sekarang karena saya telah menghapus eval()kode saya.
Bhavik Hirani
17

Ok, saya tahu ini sudah memiliki jawaban yang sangat terunggul, tetapi pertanyaan serupa lainnya diajukan baru-baru ini, dan saya juga diarahkan ke pertanyaan ini. Saya juga ingin menawarkan solusi saya, karena ia menawarkan keuntungan dibandingkan solusi yang diterima: Anda dapat menyertakan elemen formulir yang dinonaktifkan (yang kadang-kadang penting, tergantung pada bagaimana fungsi UI Anda)

Ini jawaban saya dari pertanyaan SO lainnya :

Awalnya, kami menggunakan serializeArray()metode jQuery , tetapi itu tidak termasuk elemen formulir yang dinonaktifkan. Kami akan sering menonaktifkan elemen formulir yang "disinkronkan" ke sumber lain di halaman, tetapi kami masih perlu memasukkan data ke objek serial kami. Begitu serializeArray()juga keluar. Kami menggunakan :inputpemilih untuk mendapatkan semua elemen input (baik diaktifkan dan dinonaktifkan) dalam wadah yang diberikan, dan kemudian $.map()untuk membuat objek kami.

var inputs = $("#container :input");
var obj = $.map(inputs, function(n, i)
{
    var o = {};
    o[n.name] = $(n).val();
    return o;
});
console.log(obj);

Perhatikan bahwa agar ini berfungsi, setiap input Anda akan memerlukan nameatribut, yang akan menjadi nama properti dari objek yang dihasilkan.

Itu sebenarnya sedikit dimodifikasi dari apa yang kami gunakan. Kami perlu membuat objek yang terstruktur sebagai .NET IDictionary, jadi kami menggunakan ini: (Saya berikan di sini jika berguna)

var obj = $.map(inputs, function(n, i)
{
    return { Key: n.name, Value: $(n).val() };
});
console.log(obj);

Saya suka kedua solusi ini, karena mereka adalah penggunaan $.map()fungsi yang sederhana , dan Anda memiliki kontrol penuh atas pemilih Anda (jadi, elemen mana yang Anda akhirnya termasuk dalam objek yang Anda hasilkan). Juga, tidak diperlukan plugin tambahan. JQuery tua polos.

Samuel Meacham
sumber
6
Saya mencoba ini dalam sebuah proyek, menggunakan mapseperti ini menciptakan array objek dengan satu properti, tidak meruntuhkan semua properti menjadi satu objek.
joshperry
16

Fungsi ini harus menangani array multidimensi bersama dengan beberapa elemen dengan nama yang sama.

Saya telah menggunakannya selama beberapa tahun sejauh ini:

jQuery.fn.serializeJSON=function() {
  var json = {};
  jQuery.map(jQuery(this).serializeArray(), function(n, i) {
    var _ = n.name.indexOf('[');
    if (_ > -1) {
      var o = json;
      _name = n.name.replace(/\]/gi, '').split('[');
      for (var i=0, len=_name.length; i<len; i++) {
        if (i == len-1) {
          if (o[_name[i]]) {
            if (typeof o[_name[i]] == 'string') {
              o[_name[i]] = [o[_name[i]]];
            }
            o[_name[i]].push(n.value);
          }
          else o[_name[i]] = n.value || '';
        }
        else o = o[_name[i]] = o[_name[i]] || {};
      }
    }
    else {
      if (json[n.name] !== undefined) {
        if (!json[n.name].push) {
          json[n.name] = [json[n.name]];
        }
        json[n.name].push(n.value || '');
      }
      else json[n.name] = n.value || '';      
    }
  });
  return json;
};
Sergey Varlamov
sumber
15

Kamu bisa melakukan ini:

var frm = $(document.myform);
var data = JSON.stringify(frm.serializeArray());

Lihat JSON .

Harini Sekar
sumber
14

One-liner (tidak ada dependensi selain jQuery), menggunakan pengikatan objek tetap untuk fungsi yang diteruskan ke mapmetode.

$('form').serializeArray().map(function(x){this[x.name] = x.value; return this;}.bind({}))[0]

Apa itu?

"id=2&value=1&comment=ok" => Object { id: "2", value: "1", comment: "ok" }

cocok untuk aplikasi web progresif (orang dapat dengan mudah mendukung aksi pengiriman formulir reguler serta permintaan ajax)

test30
sumber
12

Menggunakan:

function form_to_json (selector) {
  var ary = $(selector).serializeArray();
  var obj = {};
  for (var a = 0; a < ary.length; a++) obj[ary[a].name] = ary[a].value;
  return obj;
}

Keluaran:

{"myfield": "myfield value", "passwordfield": "mypasswordvalue"}
Adrian Seeley
sumber
7

Kesederhanaan adalah yang terbaik di sini. Saya telah menggunakan pengganti string sederhana dengan ekspresi reguler, dan mereka bekerja seperti pesona sejauh ini. Saya bukan ahli ekspresi reguler, tetapi saya yakin Anda bahkan dapat mengisi objek yang sangat kompleks.

var values = $(this).serialize(),
attributes = {};

values.replace(/([^&]+)=([^&]*)/g, function (match, name, value) {
    attributes[name] = value;
});
ngr
sumber
7

Dari beberapa jawaban yang lebih tua :

$('form input, form select').toArray().reduce(function(m,e){m[e.name] = $(e).val(); return m;},{})
juanpastas
sumber
Dari apa yang dapat saya katakan, perbedaannya adalah bahwa solusi Anda tidak bergantung pada serializeArraysehingga Anda memiliki kebebasan untuk memilih input apa pun yang Anda inginkan (mis. Anda dapat memasukkan input yang dinonaktifkan), kan? Yaitu ini tidak digabungkan ke bentuk apa pun atau ajukan acara, itu hanya independen dengan sendirinya?
dvtan
satu-satunya perbedaan kecil dengan jawaban tertaut adalah bahwa tidak ada data yang diperlukan untuk instantiate, reducemengembalikan objek. Ini tidak independen karena toArrayberasal dari jQuery.
situs
6

Saya menemukan masalah dengan kode Tobias Cohen (saya tidak punya cukup poin untuk mengomentarinya secara langsung), yang jika tidak berfungsi untuk saya. Jika Anda memiliki dua opsi pilih dengan nama yang sama, keduanya dengan nilai = "", kode asli akan menghasilkan "nama": "" bukannya "nama": ["", ""]

Saya pikir ini dapat diperbaiki dengan menambahkan "|| o [this.name] == ''" ke kondisi if pertama:

$.fn.serializeObject = function()
{
    var o = {};
    var a = this.serializeArray();
    $.each(a, function() {
        if (o[this.name] || o[this.name] == '') {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
};
pengguna1134789
sumber
6

Menggunakan solusi maček , saya memodifikasinya agar berfungsi dengan cara ASP.NET MVC menangani objek bersarang / kompleks pada formulir yang sama. Yang harus Anda lakukan adalah memodifikasi bagian validasi untuk ini:

"validate": /^[a-zA-Z][a-zA-Z0-9_]*((?:\[(?:\d*|[a-zA-Z0-9_]+)\])*(?:\.)[a-zA-Z][a-zA-Z0-9_]*)*$/,

Ini akan cocok dan kemudian memetakan elemen dengan nama seperti:

<input type="text" name="zooName" />

Dan

<input type="text" name="zooAnimals[0].name" />
G-Ram
sumber
5

cara paling sederhana dan paling akurat saya ditemukan untuk masalah ini adalah menggunakan bbq Plugin atau ini salah satu (yaitu sekitar 0.5K byte ukuran).

ini juga bekerja dengan array multi dimensi.

$.fn.serializeObject = function()
{
	return $.deparam(this.serialize());
};

Roey
sumber
Ini sepertinya bekerja dengan baik. Ada repositori alternatif untuk jquery-deparam yang mencakup file deskripsi untuk bower dan npm.
Alf Eaton
4

Ada plugin untuk melakukannya untuk jQuery, jquery.serializeJSON . Saya telah menggunakannya dengan sukses pada beberapa proyek sekarang. Itu bekerja seperti pesona.

Peter Mortensen
sumber
4
const formData = new FormData(form);

let formDataJSON = {};

for (const [key, value] of formData.entries()) {

    formDataJSON[key] = value;
}
Stonetip
sumber
3

Saya lebih suka pendekatan ini karena: Anda tidak perlu mengulangi lebih dari 2 koleksi, Anda bisa mendapatkan hal-hal selain "nama" dan "nilai" jika Anda perlu, dan Anda dapat membersihkan nilai-nilai Anda sebelum menyimpannya di objek ( jika Anda memiliki nilai default yang tidak ingin Anda simpan, misalnya).

$.formObject = function($o) {
    var o = {},
        real_value = function($field) {
            var val = $field.val() || "";

            // additional cleaning here, if needed

            return val;
        };

    if (typeof o != "object") {
        $o = $(o);
    }

    $(":input[name]", $o).each(function(i, field) {
        var $field = $(field),
            name = $field.attr("name"),
            value = real_value($field);

        if (o[name]) {
            if (!$.isArray(o[name])) {
                o[name] = [o[name]];
            }

            o[name].push(value);
        }

        else {
            o[name] = value;
        }
    });

    return o;
}

Gunakan seperti ini:

var obj = $.formObject($("#someForm"));

Hanya diuji di Firefox.

kflorence
sumber
3

Mengubah apa pun menjadi objek (bukan unit yang diuji)

<script type="text/javascript">
string = {};

string.repeat = function(string, count)
{
    return new Array(count+1).join(string);
}

string.count = function(string)
{
    var count = 0;

    for (var i=1; i<arguments.length; i++)
    {
        var results = string.match(new RegExp(arguments[i], 'g'));
        count += results ? results.length : 0;
    }

    return count;
}

array = {};

array.merge = function(arr1, arr2)
{
    for (var i in arr2)
    {
        if (arr1[i] && typeof arr1[i] == 'object' && typeof arr2[i] == 'object')
            arr1[i] = array.merge(arr1[i], arr2[i]);
        else
            arr1[i] = arr2[i]
    }

    return arr1;
}

array.print = function(obj)
{
    var arr = [];
    $.each(obj, function(key, val) {
        var next = key + ": ";
        next += $.isPlainObject(val) ? array.print(val) : val;
        arr.push( next );
      });

    return "{ " +  arr.join(", ") + " }";
}

node = {};

node.objectify = function(node, params)
{
    if (!params)
        params = {};

    if (!params.selector)
        params.selector = "*";

    if (!params.key)
        params.key = "name";

    if (!params.value)
        params.value = "value";

    var o = {};
    var indexes = {};

    $(node).find(params.selector+"["+params.key+"]").each(function()
    {
        var name = $(this).attr(params.key),
            value = $(this).attr(params.value);

        var obj = $.parseJSON("{"+name.replace(/([^\[]*)/, function()
        {
            return '"'+arguments[1]+'"';
        }).replace(/\[(.*?)\]/gi, function()
        {
            if (arguments[1].length == 0)
            {
                var index = arguments[3].substring(0, arguments[2]);
                indexes[index] = indexes[index] !== undefined ? indexes[index]+1 : 0;

                return ':{"'+indexes[index]+'"';
            }
            else
                return ':{"'+escape(arguments[1])+'"';
        })+':"'+value.replace(/[\\"]/gi, function()
        {
            return "\\"+arguments[0]; 
        })+'"'+string.repeat('}', string.count(name, ']'))+"}");

        o = array.merge(o, obj);
    });

    return o;
}
</script>

Output dari tes:

$(document).ready(function()
{
    console.log(array.print(node.objectify($("form"), {})));
    console.log(array.print(node.objectify($("form"), {selector: "select"})));
});

di

<form>
    <input name='input[a]' type='text' value='text'/>
    <select name='input[b]'>
        <option>select</option>
    </select>

    <input name='otherinput[c][a]' value='a'/>
    <input name='otherinput[c][]' value='b'/>
    <input name='otherinput[d][b]' value='c'/>
    <input name='otherinput[c][]' value='d'/>

    <input type='hidden' name='anotherinput' value='hidden'/>
    <input type='hidden' name='anotherinput' value='1'/>

    <input type='submit' value='submit'/>
</form>

akan menghasilkan:

{ input: { a: text, b: select }, otherinput: { c: { a: a, 0: b, 1: d }, d: { b: c } }, anotherinput: 1 }
{ input: { b: select } }
eithed
sumber
3

Saya menemukan masalah dengan solusi yang dipilih.

Saat menggunakan formulir yang memiliki nama berbasis array, fungsi jQuery serializeArray () benar-benar mati.

Saya memiliki kerangka kerja PHP yang menggunakan nama bidang berbasis array untuk memungkinkan formulir yang sama dimasukkan ke halaman yang sama beberapa kali dalam banyak tampilan. Ini bisa berguna untuk menambahkan, mengedit, dan menghapus keduanya pada halaman yang sama tanpa model formulir yang saling bertentangan.

Karena saya ingin mengesahkan formulir tanpa harus mengeluarkan fungsionalitas basis absolut ini, saya memutuskan untuk menulis seralizeArray saya sendiri ():

        var $vals = {};

        $("#video_edit_form input").each(function(i){
            var name = $(this).attr("name").replace(/editSingleForm\[/i, '');

            name = name.replace(/\]/i, '');

            switch($(this).attr("type")){
                case "text":
                    $vals[name] = $(this).val();
                    break;
                case "checkbox":
                    if($(this).attr("checked")){
                        $vals[name] = $(this).val();
                    }
                    break;
                case "radio":
                    if($(this).attr("checked")){
                        $vals[name] = $(this).val();
                    }
                    break;
                default:
                    break;
            }
        });

Harap dicatat: Ini juga berfungsi di luar form submit () jadi jika kesalahan terjadi di sisa kode Anda, form tidak akan mengirimkan jika Anda menempatkan pada tombol tautan yang mengatakan "simpan perubahan".

Perhatikan juga bahwa fungsi ini tidak boleh digunakan untuk memvalidasi formulir hanya untuk mengumpulkan data yang akan dikirim ke sisi server untuk validasi. Menggunakan kode yang lemah dan banyak yang ditugaskan seperti itu AKAN menyebabkan XSS , dll.

Sammaye
sumber
3

Saya memiliki masalah yang sama belakangan ini dan keluar dengan plugin .toJSON jQuery ini yang mengubah formulir menjadi objek JSON dengan struktur yang sama. Ini juga berguna secara khusus untuk formulir yang dihasilkan secara dinamis di mana Anda ingin membiarkan pengguna Anda menambahkan lebih banyak bidang di tempat-tempat tertentu.

Intinya adalah Anda mungkin benar-benar ingin membangun formulir sehingga memiliki struktur itu sendiri, jadi katakanlah Anda ingin membuat formulir di mana pengguna memasukkan tempat favoritnya di kota: Anda dapat membayangkan formulir ini untuk mewakili <places>...</places>elemen XML yang mengandung daftar tempat yang disukai pengguna sehingga daftar <place>...</place>elemen yang masing-masing berisi misalnya <name>...</name>elemen, <type>...</type>elemen dan kemudian daftar <activity>...</activity>elemen untuk mewakili aktivitas yang dapat Anda lakukan di tempat seperti itu. Jadi struktur XML Anda akan seperti ini:

<places>

    <place>

        <name>Home</name>
        <type>dwelling</type>

        <activity>sleep</activity>
        <activity>eat</activity>
        <activity>watch TV</activity>

    </place>

    <place>...</place>

    <place>...</place>

</places>

Betapa kerennya memiliki objek JSON dari ini yang akan mewakili struktur yang tepat ini sehingga Anda dapat:

  • Simpan objek ini seperti di basis data apa pun yang mirip CouchDB
  • Baca dari sisi server $ _POST [] Anda dan coba kembali larik bersarang dengan benar yang kemudian dapat Anda manipulasi secara semantik
  • Gunakan beberapa skrip sisi server untuk mengonversinya menjadi file XML yang terbentuk dengan baik (bahkan jika Anda tidak tahu struktur persisnya a-priori)
  • Hanya entah bagaimana menggunakannya seperti di skrip server Node.js- seperti apa pun

OK, jadi sekarang kita perlu berpikir bagaimana suatu formulir dapat mewakili file XML.

Tentu saja <form>tag adalah root, tetapi kemudian kita memiliki <place>elemen yang merupakan wadah dan bukan elemen data itu sendiri, jadi kita tidak dapat menggunakan tag input untuk itu.

Di sinilah <fieldset>tag berguna! Kami akan menggunakan <fieldset>tag untuk mewakili semua elemen wadah dalam formulir / representasi XML kami, sehingga mencapai hasil seperti ini:

<form name="places">

    <fieldset name="place">

        <input type="text" name="name"/>
        <select name="type">
            <option value="dwelling">Dwelling</option>
            <option value="restoration">Restoration</option>
            <option value="sport">Sport</option>
            <option value="administrative">Administrative</option>
        </select>

        <input type="text" name="activity"/>
        <input type="text" name="activity"/>
        <input type="text" name="activity"/>

    </fieldset>

</form>

Seperti yang Anda lihat dalam formulir ini, kami melanggar aturan nama unik, tetapi ini OK karena mereka akan dikonversi menjadi array elemen sehingga mereka akan dirujuk hanya dengan indeks mereka di dalam array.

Pada titik ini Anda dapat melihat bagaimana tidak ada name="array[]"nama seperti di dalam formulir dan semuanya cantik, sederhana dan semantik.

Sekarang kami ingin formulir ini dikonversi menjadi objek JSON yang akan terlihat seperti ini:

{'places':{

    'place':[

        {

            'name': 'Home',
            'type': 'dwelling',

            'activity':[

                 'sleep',
                 'eat',
                 'watch TV'

            ]

        },

        {...},

        {...}

    ]

}}

Untuk melakukan ini, saya telah mengembangkan plugin jQuery ini di sini di mana seseorang membantu mengoptimalkan dalam utas Tinjauan Kode ini dan terlihat seperti ini:

$.fn.toJSO = function () {
    var obj = {},
        $kids = $(this).children('[name]');
    if (!$kids.length) {
        return $(this).val();
    }
    $kids.each(function () {
        var $el = $(this),
            name = $el.attr('name');
        if ($el.siblings("[name=" + name + "]").length) {
            if (!/radio|checkbox/i.test($el.attr('type')) || $el.prop('checked')) {
                obj[name] = obj[name] || [];
                obj[name].push($el.toJSO());
            }
        } else {
            obj[name] = $el.toJSO();
        }
    });
    return obj;
};

Saya juga membuat posting blog yang satu ini untuk menjelaskan hal ini lebih lanjut.

Ini mengonversi semuanya dalam bentuk menjadi JSON (bahkan radio dan kotak centang) dan yang harus Anda lakukan hanyalah menelepon

$.post('script.php',('form').toJSO(), ...);

Saya tahu ada banyak cara untuk mengubah bentuk menjadi objek JSON dan tentu saja .serialize()dan .serializeArray()berfungsi dengan baik dalam banyak kasus dan sebagian besar dimaksudkan untuk digunakan, tapi saya pikir seluruh gagasan ini menulis formulir sebagai struktur XML dengan nama yang bermakna dan mengubahnya menjadi objek JSON yang terbentuk dengan baik patut dicoba, juga fakta bahwa Anda dapat menambahkan tag input dengan nama yang sama tanpa khawatir sangat berguna jika Anda perlu retrive data formulir yang dihasilkan secara dinamis.

Saya harap ini membantu seseorang!

Onheiron
sumber
apa yang sedang Anda coba lakukan?
Onheiron
3

Saya mengkodekan bentuk ke objek JavaScript multidimensi sendiri untuk menggunakannya dalam produksi. Hasilnya adalah https://github.com/serbanghita/formToObject.js .

serbanghita
sumber
Saya menggunakan variasi ini untuk implementasi yang sangat spesifik, terima kasih banyak!
Chris Baker
Terima kasih telah memberi tahu saya bahwa ini berguna. Saya memiliki beberapa fitur masuk untuk bergulir dan ini memotivasi saya.
Șerban Ghiță
3

Jawaban lain

document.addEventListener("DOMContentLoaded", function() {
  setInterval(function() {
    var form = document.getElementById('form') || document.querySelector('form[name="userprofile"]');
    var json = Array.from(new FormData(form)).map(function(e,i) {this[e[0]]=e[1]; return this;}.bind({}))[0];
    
    console.log(json)
    document.querySelector('#asJSON').value = JSON.stringify(json);
  }, 1000);
})
<form name="userprofile" id="form">
  <p>Name <input type="text" name="firstname" value="John"/></p>
  <p>Family name <input name="lastname" value="Smith"/></p>
  <p>Work <input name="employment[name]" value="inc, Inc."/></p>
  <p>Works since <input name="employment[since]" value="2017" /></p>
  <p>Photo <input type="file" /></p>
  <p>Send <input type="submit" /></p>
</form>

JSON: <textarea id="asJSON"></textarea>

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

test30
sumber
3

[UPDATE 2020]

Dengan oneliner sederhana di vanilla js:

Object.fromEntries(new FormData(form))
Aret
sumber
2

Saya suka versi samuels, tetapi saya percaya ini memiliki kesalahan kecil. Biasanya JSON dikirim sebagai

{"coreSKU": "PCGUYJS", "name_de": "apa pun", ...

BUKAN sebagai

[{"coreSKU": "PCGUYJS"}, {"name_de": "whatever"}, ...

jadi fungsi IMO harus membaca:

App.toJson = function( selector ) {
    var o = {};
    $.map( $( selector ), function( n,i )
    {
        o[n.name] = $(n).val();
    });     
    return o;
}

dan untuk membungkusnya dalam array data (seperti yang diharapkan juga), dan akhirnya mengirimkannya sebagai App.stringify astring ({data: App.toJson ('#cropform: input')})

Untuk tampilan ketat pada Pertanyaan 3593046 untuk versi ramping, di json2.js untuk setiap versi yang tercakup pada setiap acara. Itu harus mencakup semuanya :)

Frank Nocke
sumber
Terima kasih .. ini membuat (seperti yang Anda sebutkan) kecil tapi sangat penting.
Adarsha
2

Untuk solusi cepat dan modern, gunakan plugin JSONify jQuery. Contoh di bawah ini diambil kata demi kata dari GitHub README. Semua kredit untuk Kushal Pandya, penulis plugin.

Diberikan:

<form id="myform">
    <label>Name:</label>
    <input type="text" name="name"/>
    <label>Email</label>
    <input type="text" name="email"/>
    <label>Password</label>
    <input type="password" name="password"/>
</form>

Berlari:

$('#myform').jsonify();

Menghasilkan:

{"name":"Joe User","email":"[email protected]","password":"mypass"}

Jika Anda ingin melakukan jQuery POST dengan objek JSON ini:

$('#mybutton').click(function() {
    $.post('/api/user', JSON.stringify($('#myform').jsonify()));
}
Jim Stewart
sumber