Преобразование данных формы в объект JavaScript с помощью jQuery

avatar
Yisroel
26 июля 2009 в 13:39
1032491
59
1691

Как преобразовать все элементы формы в объект JavaScript?

Я хотел бы иметь какой-нибудь способ автоматического создания объекта JavaScript из моей формы без необходимости перебирать каждый элемент в цикле. Мне не нужна строка, возвращаемая $('#formid').serialize();, и карта, возвращаемая $('#formid').serializeArray();

Источник
meder omuraliev
26 июля 2009 в 13:43
0

Я не понимаю, почему один из этих методов подходит для ваших нужд?

Yisroel
26 июля 2009 в 14:05
16

потому что первый возвращает строку, точно такую ​​же, как если бы вы отправили форму с помощью метода GET, а второй дает вам массив объектов, каждый из которых имеет пару имя-значение. Я хочу, чтобы если у меня есть поле с именем «электронная почта», я получил объект, который позволит мне получить это значение с помощью obj.email. С serializeArray () мне нужно было бы сделать что-то вроде obj [indexOfElement] .value

serg
26 июля 2009 в 17:01
0

Если вы пытаетесь преобразовать все поля формы в JSON, чтобы отправить эту форму через Ajax, вот плагин формы jQuery, который делает это.

Taylor Leese
17 апреля 2010 в 16:12
0

У этого вопроса есть лучшее решение: coderhelper.com/questions/191881/…

James McCormack
22 декабря 2010 в 12:41
1

@Taylor Я не вижу там ответа, который бы отвечал на конкретный вопрос лучше, чем ответ Тобиаса ниже.

Taylor Leese
22 декабря 2010 в 20:11
2

@James - принятый ответ с использованием библиотеки JSON-js Д. Крокфорда. Вот пример: github.com/tleese22/google-app-engine-jappstart/blob/master/src/…

James McCormack
23 декабря 2010 в 12:30
4

@Taylor Да, я бы сказал, что в правильном ответе используются функции Crockford lib и Tobias, например: JSON.stringify ($ ('myForm'). SerializeObject ())

maček
6 декабря 2011 в 21:55
1

ГОЛОСОВАТЬ 100! Наслаждайтесь своим значком :)

Jon z
21 мая 2012 в 16:12
0

Все приведенные ниже методы безумны, просто используйте $ .serialize, он передается как в POST, так и в GET.

Patrick M
9 июля 2012 в 14:11
5

@Jonz - Есть и другие причины, помимо отправки / передачи, для использования элемента формы. Если вы занимаетесь тяжелой работой со значениями формы в JavaScript (например, одностраничное приложение), очень удобно иметь их в объектном формате для доступа и управления. Кроме того, строки запроса HTTP Post и Get - не единственные форматы для перемещения данных.

Bongs
2 марта 2013 в 21:56
3

Хороший js, с которым я столкнулся >> github.com/marioizquierdo/jquery.serializeJSON

Boggin
5 августа 2015 в 14:26
0

@TaylorLeese ссылка в вашем комментарии теперь 404.

Erics
12 января 2017 в 00:17
0

@Yisroel Это возможно, но не удастся для форм, которые имеют несколько входов с одинаковым значением имени (например, name="foo[]"). Оба .serialize () и .serializeArray () обрабатывают этот случай. Я предполагаю, что ваш конкретный вариант использования не использует этот шаблон.

Bhavik Hirani
27 февраля 2018 в 19:32
1

проверьте это coderhelper.com/a/39248551/6293856

Zaz
2 декабря 2019 в 19:09
0

$ ('# formid'). serializeArray (). reduce ((o, p) => ({... o, [p.name]: p.value}))

Ответы (59)

avatar
Tobias Cohen
19 августа 2020 в 08:54
1699

serializeArray уже делает именно это. Вам просто нужно преобразовать данные в требуемый формат:

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

Остерегайтесь скрытых полей, имена которых совпадают с именами реальных входов, поскольку они будут перезаписаны.

Tobias Cohen
28 июля 2009 в 03:05
70

Вы имеете в виду «зачем вообще использовать serializeArray для получения данных?» Поскольку serializeArray уже написан, прошел модульное тестирование в нескольких браузерах и теоретически может быть улучшен в более поздних версиях jQuery. Чем меньше кода вы напишете, который должен напрямую обращаться к несогласованным вещам, таким как элементы DOM, тем более стабильным будет ваш код.

Samuel Meacham
18 июля 2010 в 23:54
58

Имейте в виду, что serializeArray () не будет включать отключенные элементы. Я часто отключаю элементы ввода, которые синхронизируются с другими элементами на странице, но я все равно хочу, чтобы они были включены в мой сериализованный объект. Вам лучше использовать что-то вроде $.map( $("#container :input"), function(n, i) { /* n.name and $(n).val() */ } );, если вам нужно включить отключенные элементы.

avatar
26 октября 2021 в 21:11
1

Сериализация глубоко вложенных форм Без JQuery

Потратив пару дней на поиск решения этой проблемы, которое не имеет зависимостей, я решил создать сериализатор данных формы без jQuery, используя FormData API.

Логика сериализатора в значительной степени основана на функции de-param из подключаемого модуля jQuery под названием jQuery BBQ, однако в этом проекте все зависимости были удалены.

Этот проект можно найти на NPM и Github:

https://github.com/GistApps/deep-serialize-form

https://www.npmjs.com/package/deep-serialize-form

function deepSerializeForm(form) {

  var obj = {};

  var formData = new FormData(form);

  var coerce_types = { 'true': !0, 'false': !1, 'null': null };

  /**
   * Get the input value from the formData by key
   * @return {mixed}
   */
  var getValue = function(formData, key) {

    var val = formData.get(key);

    val = val && !isNaN(val)              ? +val              // number
        : val === 'undefined'             ? undefined         // undefined
        : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null
        : val;                                                // string

    return val;
  }

  for (var key of formData.keys()) {

    var val  = getValue(formData, key);
    var cur  = obj;
    var i    = 0;
    var keys = key.split('][');
    var keys_last = keys.length - 1;


    if (/\[/.test(keys[0]) && /\]$/.test(keys[keys_last])) {

      keys[keys_last] = keys[keys_last].replace(/\]$/, '');

      keys = keys.shift().split('[').concat(keys);

      keys_last = keys.length - 1;

    } else {

      keys_last = 0;
    }


    if ( keys_last ) {

      for (; i <= keys_last; i++) {
        key = keys[i] === '' ? cur.length : keys[i];
        cur = cur[key] = i < keys_last
        ? cur[key] || (keys[i+1] && isNaN(keys[i+1]) ? {} : [])
        : val;
      }

    } else {

      if (Array.isArray(obj[key])) {

        obj[key].push( val );

      } else if (obj[key] !== undefined) {

        obj[key] = [obj[key], val];

      } else {

        obj[key] = val;

      }

    }

  }

  return obj;

}

window.deepSerializeForm = deepSerializeForm;
avatar
27 августа 2021 в 14:59
0

Похоже, эта тема стала коллективным FAQ по сериализации форм :)

Мое отношение к именованию PHP: <input name="user[name]" >

$('form').on('submit', function(ev) {
   ev.preventDefault();

   var obj = $(this).serializePHPObject();

   // $.post('./', obj);
});
(function ($) {
  // based on https://coderhelper.com/a/25239999/1644202

  // <input name="user[name]" >
  $.fn.serializePHPObject = function () {
    var obj = {};
    $.each(this.serializeArray(), function (i, pair) {
      var cObj = obj,
        pObj,
        cpName;
      $.each(pair.name.split("["), function (i, pName) {
        pName = pName.replace("]", "");
        pObj = cObj;
        cpName = pName;
        cObj = cObj[pName] ? cObj[pName] : (cObj[pName] = {});
      });
      pObj[cpName] = pair.value;
    });
    return obj;
  };
})(jQuery);
avatar
10 августа 2021 в 16:39
0

Здесь используется метод foreach для перебора пары имени и значения, возвращаемой serializeArray, а затем возврата объекта, используя имена в качестве ключа.

  let formData = $(this).serializeArray();
  let formObject = {}
  formData.forEach(
    x=>formObject.hasOwnProperty(x.name)?formObject[x.name]=[formObject[x.name],x.value].flat():formObject[x.name]=x.value
  );
avatar
30 июля 2021 в 20:42
0

Это обрабатывает несколько элементов select или даже элементов с одинаковым именем:

$.fn.formToJSON = function(){
    pairStr=this.serialize();
    let rObj={};
    pairStr.split(`&`).forEach((vp)=> {
        prop=vp.split(`=`)[0];
        val=vp.split(`=`)[1];
        if(rObj.hasOwnProperty(prop)) {
            if (Array.isArray(rObj[prop])) {
                rObj[prop].push(val);
            } else {
                rObj[prop]=[rObj[prop]];
                rObj[prop].push(val);
            }
        } else {
            rObj[prop]=val;
        }
    });
    return JSON.stringify(rObj);
}
avatar
16 июня 2021 в 15:20
0
function serializedArray2Object(array){
    let obj = {};
    array.forEach(function(item){
        if(obj[item['name']] === undefined){
            obj[item['name']] = item['value'];
        }else if(Array.isArray(obj[item['name']])){
            obj[item['name']] = [...obj[item['name']],item['value']]
        }else{
            obj[item['name']] = [obj[item['name']],item['value']];
        }
    });
    return obj;
}

с использованием

serializedArray2Object($('#form').serializeArray())

Я только что обнаружил эту функцию из jQuery и написал преобразователь в объект, чтобы массив стал объектом.

avatar
MohsenB
13 мая 2021 в 09:23
0

Этот код преобразует и сохраняет тип входных данных и не преобразует все в строку:

jQuery.fn.serializeForm = function () {
    var form = this.get(0);
    var i = [];
    var ret = {};
    for (i = form.elements.length - 1; i >= 0; i = i - 1) {
        if (form.elements[i].name === "") {
            continue;
        }
        var name = form.elements[i].name;
        switch (form.elements[i].nodeName) {
            case 'INPUT':
                switch (form.elements[i].type) {
                    case 'text':
                    case 'tel':
                    case 'email':
                    case 'hidden':
                    case 'password':
                        ret[name] = encodeURIComponent(form.elements[i].value);
                        break;
                    case 'checkbox':
                    case 'radio':
                        ret[name] = form.elements[i].checked;
                        break;
                    case 'number':
                        ret[name] = parseFloat(form.elements[i].value);
                        break;
                }
                break;
            case 'SELECT':
            case 'TEXTAREA':
                ret[name] = encodeURIComponent(form.elements[i].value);
                break;
        }
    }
    return ret;
};

Например, это вывод:

Day: 13
Key: ""
Month: 5
OnlyPayed: true
SearchMode: "0"
Year: 2021

вместо

Day: "13"
Key: ""
Month: "5"
OnlyPayed: "true"
SearchMode: "0"
Year: "2021"
avatar
29 декабря 2020 в 05:11
0

Возможно, для этой задачи вам не понадобится jQuery. FormData - идеальное решение для этого.

Вот код, который использует FormData для сбора входных значений и использует dot-prop для преобразования значений во вложенные объекты.

Демонстрация CodeSandbox

avatar
22 ноября 2020 в 10:49
0

Этот код работает для меня:

  var data = $('#myForm input, #myForm select, #myForm textarea').toArray().reduce(function (m, e) {
            m[e.name] = $(e).val();
            return m;
        }, {});
avatar
aret
16 июня 2020 в 15:59
25

[ОБНОВЛЕНИЕ 2020]

С помощью простого oneliner в vanilla js, который использует fromEntries (как всегда, проверьте поддержку браузера):

Object.fromEntries(new FormData(form))
avatar
Bhavik Hirani
25 мая 2020 в 17:00
22

Я проверил, есть ли проблема со всеми остальными ответами, что если имя входа представляет собой массив, например name[key], то оно должно быть сгенерировано следующим образом:

name:{ key : value }


Например: Если у вас есть HTML-форма, аналогичная приведенной ниже:

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

Но он должен быть сгенерирован так же, как JSON ниже, и не становится объектом, подобным следующему, со всеми другими ответами. Так что, если кто-то хочет принести что-то вроде следующего JSON, попробуйте приведенный ниже код JS.

{
    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>
Leonardo Beal
14 февраля 2018 в 16:06
0

Этот ответ касается упомянутого случая, но не касается таких случаев, как checkbox [] или даже one [another] [another_one]

Bhavik Hirani
27 февраля 2018 в 19:30
1

@LeonardoBeal, я исправлю свой ответ .. проверьте это сейчас ..!

Jack Giffin
31 июля 2019 в 21:04
0

Я проголосовал против, потому что eval не следует использовать таким образом, потому что eval при таком использовании способствует ужасно ненадежным, ошибочным, неэффективным и потенциально небезопасным методам.

iRaS
27 ноября 2019 в 09:11
2

Не могу согласиться, что это хороший ответ. И, пожалуйста, при написании ответов сделайте свой код понятным или объясните его. this.c = function(k,v){ eval("c = typeof "+k+";"); if(c == 'undefined') _t.b(k,v);} является кратким и не поясняющим. Менее опытный разработчик просто скопирует это, не понимая, почему и как это работает.

Bhavik Hirani
25 мая 2020 в 17:02
2

@JackGiffin Ознакомьтесь с моим новым кодом сейчас, потому что я удалил из своего кода eval().

Burhan Kashour
7 июля 2021 в 09:31
1

@BhavikHirani После долгих поисков я нашел ваш ответ, вы сэкономили мне долгие часы поиска! Спасибо чувак!!

Bhavik Hirani
22 июля 2021 в 12:29
0

@BurhanKashour добро пожаловать в любое время, пожалуйста, не забудьте проголосовать!

avatar
24 февраля 2020 в 08:03
2

Использование преимуществ ES6 в одном лайнере:

$("form").serializeArray().reduce((o, {name: n, value: v}) => Object.assign(o, { [n]: v }), {});
avatar
2 декабря 2019 в 19:07
2

Вот однострочник с использованием reduce . Reduce - это функциональная функция, которая принимает возвращаемое значение переданной функции и передает его обратно в переданную функцию на следующей итерации вместе с n-м значением из списка.

$('#formid').serializeArray().reduce((o,p) => ({...o, [p.name]: p.value}))

Мы должны использовать несколько приемов, чтобы заставить это работать:

  • ...o (синтаксис распространения) вставляет все пары key: value из o
  • Оберните возвращаемый объект в (), чтобы отличить его от {}, обозначающего функцию
  • Оберните ключ (p.name) в []
Paflow
25 февраля 2020 в 10:57
3

Я получаю неверный результат, если не добавляю к этой функции объект инициализации: $ ('form'). SerializeArray (). Reduce ((o, p) => ({... o, [p.name] : p.value}), {})

avatar
maček
29 ноября 2019 в 18:21
461

Преобразование форм в JSON как босс


Текущий источник: на GitHub и Bower.

$ bower install jquery-serialize-object


Следующий код теперь устарел .

Следующий код может работать со всеми видами имен входов; и обработайте их так, как вы ожидаете.

Например:

<!-- 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"
          }
        }
      }
    }
  }
}

Использование

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

Волшебство (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);
frontendbeauty
29 декабря 2011 в 00:44
17

Итак, это работает очень хорошо. Но он неправильно назван: он не возвращает JSON, как следует из названия. Вместо этого он возвращает литерал объекта. Кроме того, важно проверить hasOwnProperty, иначе ваши массивы будут иметь все, что связано с их прототипом, например: {numbers: ["1", "3", indexOf: function () {...}]}

avatar
3 сентября 2019 в 09:38
0

Javascript / jQuery однострочный - который работает и в более старых версиях (до ES6):

$('form').serializeArray().reduce((f,c) => {f[c['name']]=(f[c['name']])?[].concat(f[c['name']],c['value']):c['value']; return f}, {} );
avatar
juanpastas
5 февраля 2019 в 07:56
7

Из более старого ответа:

$('form input, form select').toArray().reduce(function(m,e){m[e.name] = $(e).val(); return m;},{})
davidtgq
27 мая 2016 в 01:12
0

Насколько я могу судить, разница в том, что ваше решение не зависит от serializeArray, поэтому у вас есть свобода выбора любых входов, которые вы хотите (например, вы можете включить отключенные входы), верно? Т.е. это не связано с какой-либо формой или событием отправки, оно просто независимо само по себе?

sites
27 мая 2016 в 15:09
0

единственная небольшая разница со связанным ответом заключается в том, что для создания экземпляра данных не требуется, reduce возвращает объект. Это не является независимым, поскольку toArray взят из jQuery.

avatar
24 мая 2018 в 20:42
5
const formData = new FormData(form);

let formDataJSON = {};

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

    formDataJSON[key] = value;
}
avatar
test30
2 апреля 2018 в 16:36
4

Другой ответ

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

avatar
22 марта 2018 в 13:33
1

Более современный способ - использовать сокращение с serializeArray() следующим образом:

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

Это поможет во многих «обычных» случаях.

Для очень распространенного случая, когда есть несколько тегов с повторяющимися атрибутами name, этого недостаточно.

Поскольку входные данные с повторяющимися атрибутами name обычно находятся внутри некоторой «оболочки» (div, ul, tr, ...), как в этом примере:

  <div class="wrapperClass">
    <input type="text" name="one">
    <input type="text" name="two">
  </div>
  <div class="wrapperClass">
    <input type="text" name="one">
    <input type="text" name="two">
  </div>

можно использовать сокращение с оператором map для итерации по ним:

$(".wrapperClass").map(function () {
  return $(this).find('*').serializeArray()
    .reduce((a, x) => ({ ...a, [x.name]: x.value }), {});
}).get();

Результатом будет массив объектов в формате:

  [
    {
      one: valueOfOne,
      two: valueOfTwo
    }, {
      one: valueOfOne,
      two: valueOfTwo
    }
  ]

Оператор .get() используется вместе с map для получения базового массива вместо объекта jQuery, что дает более чистый результат. документы jQuery

avatar
16 октября 2017 в 11:35
13

Однострочный (без зависимостей, кроме jQuery), использует фиксированную привязку объекта для функции, переданной методу map.

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

Что он делает?

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

подходит для прогрессивных веб-приложений (можно легко поддерживать как обычные действия отправки формы, так и запросы ajax)

avatar
8 октября 2017 в 13:59
1

Итак, я использовал принятый ответ и обнаружил серьезную ошибку.
Он не поддерживает такие входные массивы, как:

<input type="checkbox" name="array[]" value="1"/>
<input type="checkbox" name="array[]" value="2"/>
<input type="checkbox" name="array[]" value="3"/>

Это небольшое изменение должно исправить следующее:

function objectifyForm(inp){
    var rObject = {};
    for (var i = 0; i < inp.length; i++){
        if(inp[i]['name'].substr(inp[i]['name'].length - 2) == "[]"){
            var tmp = inp[i]['name'].substr(0, inp[i]['name'].length-2);
            if(Array.isArray(rObject[tmp])){
                rObject[tmp].push(inp[i]['value']);
            } else{
                rObject[tmp] = [];
                rObject[tmp].push(inp[i]['value']);
            }
        } else{
            rObject[inp[i]['name']] = inp[i]['value'];
        }
    }
    return rObject;
}

Не забудьте передать ему вывод из $(this).serializeArray();, иначе он не будет работать.

avatar
Frank Nocke
23 мая 2017 в 12:18
2

Мне нравится версия Samuels, но я считаю, что в ней есть небольшая ошибка. Обычно JSON отправляется как

{"coreSKU": "PCGUYJS", "name_de": "что угодно", ...

НЕ как

[{"coreSKU": "PCGUYJS"}, {"name_de": "что угодно"}, ...

, поэтому функция IMO должна выглядеть так:

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

и обернуть его в массив данных (как обычно ожидается) и, наконец, отправить его как строку App.stringify ({данные: App.toJson ('#cropform: input')})

Для преобразования в строку смотрите Вопрос 3593046 для упрощенной версии, на json2.js для версии, охватываемой всеми возможными случаями. Это должно покрыть все :)

Adarsha
27 апреля 2018 в 18:00
0

Спасибо .. это имеет (как вы упомянули) крошечную, но очень важную разницу.

avatar
Samuel Meacham
23 мая 2017 в 11:55
19

Хорошо, я знаю, что этот ответ уже получил много голосов, но недавно был задан другой аналогичный вопрос, и я был направлен на этот вопрос. Я также хотел бы предложить свое решение, потому что оно предлагает преимущество перед принятым решением: вы можете включать отключенные элементы формы (что иногда важно, в зависимости от того, как работает ваш пользовательский интерфейс)

Вот мой ответ на другой вопрос SO:

Первоначально мы использовали метод jQuery serializeArray(), но он не включает отключенные элементы формы. Мы часто отключаем элементы формы, которые «синхронизируются» с другими источниками на странице, но нам все равно нужно включать данные в наш сериализованный объект. Итак, serializeArray() отсутствует. Мы использовали селектор :input, чтобы получить все входные элементы (как включенные, так и отключенные) в данном контейнере, а затем $.map(), чтобы создать наш объект.

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

Обратите внимание, что для того, чтобы это работало, каждому из ваших входных данных потребуется атрибут name, который будет именем свойства результирующего объекта.

На самом деле это немного отличается от того, что мы использовали. Нам нужно было создать объект, который был структурирован как .NET IDictionary, поэтому мы использовали это: (я предоставляю его здесь, если он будет полезен)

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

Мне нравятся оба этих решения, потому что они представляют собой простое использование функции $.map(), и вы полностью контролируете свой селектор (то есть, какие элементы вы в конечном итоге включите в полученный объект). Кроме того, не требуется дополнительных плагинов. Обычный старый jQuery.

joshperry
1 октября 2010 в 22:46
6

Я пробовал это в проекте, используя map, как будто это создает массив объектов с одним свойством, он не сворачивает все свойства в один объект.

avatar
G-Ram
23 мая 2017 в 10:31
5

Используя решение maček, я изменил его для работы с тем, как ASP.NET MVC обрабатывает свои вложенные / сложные объекты в одной и той же форме. Все, что вам нужно сделать, это изменить часть проверки на это:

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

Это будет соответствовать, а затем правильно отображать элементы с такими именами, как:

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

И

<input type="text" name="zooAnimals[0].name" />
avatar
Onheiron
13 апреля 2017 в 12:40
2

У меня была такая же проблема в последнее время, и я выпустил этот плагин jQuery .toJSON, который преобразует форму в объект JSON с той же структурой. Это также особенно полезно для динамически генерируемых форм, где вы хотите, чтобы ваш пользователь мог добавлять дополнительные поля в определенных местах.

[ <places>...</places>> XML-элемент, содержащий список мест, которые нравятся пользователю, таким образом, список из <place>...</place> элементов, каждый из которых содержит, например, элемент <name>...</name>, элемент <type>...</type>, а затем список элементов <activity>...</activity> для представления ваших действий может выступить в таком месте. Итак, ваша структура XML будет такой:

<places>

    <place>

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

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

    </place>

    <place>...</place>

    <place>...</place>

</places>

Как здорово было бы иметь объект JSON из этого, который бы представлял эту точную структуру, чтобы вы могли либо:

  • Сохраните этот объект, как он есть, в любой CouchDB -подобной базе данных
  • Прочтите его со стороны сервера $ _POST [] и получите правильно вложенный массив, который затем можно семантически манипулировать
  • Используйте какой-нибудь серверный скрипт, чтобы преобразовать его в правильно сформированный XML-файл (даже если вы заранее не знаете его точную структуру)
  • Просто используйте его как есть в любом Node.js -подобном серверном скрипте

Хорошо, теперь нам нужно подумать, как форма может представлять XML-файл.

Конечно, тег <form> - это root, но тогда у нас есть этот элемент <place>, который является контейнером, а не самим элементом данных, поэтому мы не можем использовать для него тег ввода.

Здесь пригодится тег <fieldset>! Мы будем использовать теги <fieldset> для представления всех элементов контейнера в нашей форме / XML-представлении и, таким образом, получим такой результат:

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

Как вы можете видеть в этой форме, мы нарушаем правило уникальных имен, но это нормально, потому что они будут преобразованы в массив элементов, поэтому на них будут ссылаться только их индекс внутри массива.

На этом этапе вы можете увидеть, что внутри формы нет name="array[]" подобного имени, и все выглядит красиво, просто и семантично.

Теперь мы хотим, чтобы эта форма была преобразована в объект JSON, который будет выглядеть так:

{'places':{

    'place':[

        {

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

            'activity':[

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

            ]

        },

        {...},

        {...}

    ]

}}

Для этого я разработал этот плагин jQuery здесь, который кто-то помогал оптимизировать в этой проверке кода ветке и выглядит так 929984250>

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

Я также сделал этот пост в блоге, чтобы объяснить это подробнее.

Это преобразует все в форме в JSON (даже радио и флажки), и все, что вам нужно сделать, это позвонить по номеру

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

Я знаю, что есть много способов преобразовать формы в объекты JSON, и уверен, что .serialize() и .serializeArray() отлично работают в большинстве случаев и в основном предназначены для использования, но я думаю, что вся идея написания формы поскольку XML-структура со значимыми именами и преобразование ее в правильно сформированный объект JSON стоит попробовать, а также тот факт, что вы можете добавлять одноименные входные теги, не беспокоясь, очень полезен, если вам нужно получить данные динамически сгенерированных форм .

Надеюсь, это кому-то поможет!

Onheiron
2 сентября 2013 в 10:23
0

Что ты пытаешься сделать?

avatar
Harini Sekar
16 февраля 2017 в 16:19
14

Вы можете сделать это:

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

См. JSON .

avatar
10 июня 2016 в 09:03
1

используя lodash#set

let serialized = [
  { key: 'data[model][id]', value: 1 },
  { key: 'data[model][name]', value: 'product' },
  { key: 'sid', value: 'dh0un1hr4d' }
];

serialized.reduce(function(res, item) {
  _.set(res, item.key, item.value);
  return res;
}, {});

// returns
{
  "data": {
    "model": {
      "id": 1,
      "name": "product"
    }
  },
  "sid": "dh0un1hr4d"
}
supertrue
10 апреля 2017 в 16:17
0

Мне нравится это решение, но оно не обрабатывает поля формы в формате массива key[]; [ {key: 'items[]', value: 1 }, {key: 'items[]', value: 2 } ] приводит к { items: { "": 2 } }.

avatar
Justin Levene
27 мая 2016 в 21:06
-1

Создайте карту и циклически перебирайте все поля, сохраняя их значения.

var params = {};
$("#form").find("*[name]").each(function(){
    params[this.getAttribute("name")] = this.value;
});
avatar
1 января 2016 в 18:43
-1

Эта функция возвращает все значения, преобразованные в правильный тип;

bool / string / (integer / floats) возможно

Для этого вам нужен jQuery, но поскольку serializeArray тоже является jQuery, имхо ничего страшного.

/**
 * serialized a form to a json object
 *
 * @usage: $("#myform").jsonSerialize();
 *
 */

(function($) {
    "use strict";
    $.fn.jsonSerialize = function() {
        var json = {};
        var array = $(this).serializeArray();
        $.each(array, function(key, obj) {
            var value = (obj.value == "") ? false : obj.value;
            if(value) {
                // check if we have a number
                var isNum = /^\d+$/.test(value);
                if(isNum) value = parseFloat(value);
                // check if we have a boolean
                var isBool = /^(false|true)+$/.test(value);
                if(isBool) value = (value!=="false");
            }
            json[obj.name] = value;
        });
        return json;
    }
})(jQuery);
avatar
8 декабря 2015 в 09:50
4

самый простой и точный способ решить эту проблему - использовать плагин bbq или этот один (размер которого составляет около 0,5 Кбайт).

он также работает с многомерными массивами.

$.fn.serializeObject = function()
{
	return $.deparam(this.serialize());
};
Alf Eaton
19 апреля 2016 в 14:36
0

Кажется, это действительно хорошо работает. Существует альтернативный репозиторий для jquery-deparam, который включает файлы описания для bower и npm.

avatar
28 июля 2015 в 02:18
0

Вот способ, отличный от jQuery:

    var getFormData = function(form) {
        //Ignore the submit button
        var elements = Array.prototype.filter.call(form.elements, function(element) {
            var type = element.getAttribute('type');
            return !type || type.toLowerCase() !== 'submit';
        });

Вы можете использовать это так:

function() {

    var getFormData = function(form) {
        //Ignore the submit button
        var elements = Array.prototype.filter.call(form.elements, function(element) {
            var type = element.getAttribute('type');
            return !type || type.toLowerCase() !== 'submit';
        });

        //Make an object out of the form data: {name: value}
        var data = elements.reduce(function(data, element) {
            data[element.name] = element.value;
            return data;
        }, {});

        return data;
    };

    var post = function(action, data, callback) {
        var request = new XMLHttpRequest();
        request.onload = callback;
        request.open('post', action);
        request.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
        request.send(JSON.stringify(data), true);
        request.send();
    };

    var submit = function(e) {
        e.preventDefault();
        var form = e.target;
        var action = form.action;
        var data = getFormData(form);
        //change the third argument in order to do something
        //more intersting with the response than just print it
        post(action, data, console.log.bind(console));
    }

    //change formName below
    document.formName.onsubmit = submit;

})();
avatar
tfmontague
31 мая 2015 в 07:42
0

Если вы хотите преобразовать форму в объект javascript, то самым простым решением (на данный момент) является использование методов-функций jQuery each и serializeArray.

$.fn.serializeObject = function() {

  var form = {};
  $.each($(this).serializeArray(), function (i, field) {
    form[field.name] = field.value || "";
  });

  return form;
};

Плагин, размещенный на GitHub:
https://github.com/tfmontague/form-object/blob/master/README.md <234093087349

Может быть установлен с Bower:
bower install git://github.com/tfmontague/form-object.git

avatar
Florin Mircea
27 апреля 2015 в 10:42
0

У меня недавно была такая же проблема, поэтому я разработал функцию, которая позволяет анализировать элементы управления формы для получения идентификатора / значения элемента управления и преобразования их в JSON.

Он достаточно гибкий, чтобы можно было добавлять дополнительные элементы управления. Вам просто нужно указать тип элемента управления и атрибут, который вы хотите интерпретировать как значение.

Вы можете найти полный сценарий здесь.

Преимущество состоит в том, что он берет только те данные, которые вам действительно нужны, без перетаскивания всего объекта.

Недостатком является то, что если у вас есть вложенные параметры, вам необходимо соответствующим образом префикс идентификаторов, чтобы вы могли использовать дублирующий параметр для его конкретной группы.

Надеюсь, это поможет!

avatar
Ethan Brown
26 апреля 2015 в 08:34
69

Мне нравится использовать Array.prototype.reduce, потому что он однострочный и не зависит от Underscore.js или подобных:

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

Это похоже на ответ с использованием Array.prototype.map, но вам не нужно загромождать область действия дополнительной переменной объекта. Универсальные покупки.

ВАЖНОЕ ПРИМЕЧАНИЕ : Формы с входными данными, которые имеют повторяющиеся атрибуты name, являются допустимым HTML и фактически являются обычным подходом. В этом случае использование любого из ответов в этой цепочке будет неуместным (поскольку ключи объектов должны быть уникальными).

avatar
Harini Sekar
26 апреля 2015 в 07:48
0

Если вы отправляете форму с помощью JSON, вы должны удалить [] при отправке строки. Вы можете сделать это с помощью функции jQuery serializeObject ():

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

$.fn.serializeObject = function() {
    var o = {};
    //var a = this.serializeArray();
    $(this).find('input[type="hidden"], input[type="text"], input[type="password"], input[type="checkbox"]:checked, input[type="radio"]:checked, select').each(function() {
        if ($(this).attr('type') == 'hidden') { //If checkbox is checked do not take the hidden field
            var $parent = $(this).parent();
            var $chb = $parent.find('input[type="checkbox"][name="' + this.name.replace(/\[/g, '\[').replace(/\]/g, '\]') + '"]');
            if ($chb != null) {
                if ($chb.prop('checked')) return;
            }
        }
        if (this.name === null || this.name === undefined || this.name === '')
            return;
        var elemValue = null;
        if ($(this).is('select'))
            elemValue = $(this).find('option:selected').val();
        else
            elemValue = this.value;
        if (o[this.name] !== undefined) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(elemValue || '');
        }
        else {
            o[this.name] = elemValue || '';
        }
    });
    return o;
}
avatar
Peter Mortensen
26 апреля 2015 в 07:43
4

Для jQuery есть плагин, jquery.serializeJSON . Я успешно использовал его в нескольких проектах. Работает как часы.

avatar
olleicua
26 апреля 2015 в 07:41
21

Если вы используете Underscore.js, вы можете использовать относительно краткий:

_.object(_.map($('#myform').serializeArray(), _.values))
avatar
Adrian Seeley
26 апреля 2015 в 07:38
11

Использование:

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

Вывод:

{"myfield": "myfield value", "passwordfield": "mypasswordvalue"}
avatar
Niko
26 апреля 2015 в 07:37
0

Я написал модуль jQuery, jsForm, который может делать это двунаправленным даже для довольно сложных форм (также позволяет коллекции и другие более сложные структуры).

Он использует имя полей (плюс несколько специальных классов для коллекций) и соответствует объекту JSON. Позволяет автоматически реплицировать DOM-элементы для коллекций и обработки данных:

<html>
    <head>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
        <script src="https://raw.github.com/corinis/jsForm/master/src/jquery.jsForm.js"></script>
        <script>
        $(function(){
            // Some JSON data
            var jsonData = {
                name: "TestName",   // Standard inputs
                description: "long Description\nMultiline", // Textarea
                links: [{href:'http://coderhelper.com',description:'StackOverflow'}, {href:'http://www.github.com', description:'GitHub'}],   // Lists
                active: true,   // Checkbox
                state: "VISIBLE"    // Selects (enums)
            };

            // Initialize the form, prefix is optional and defaults to data
            $("#details").jsForm({
                data:jsonData
            });

            $("#show").click(function() {
                // Show the JSON data
                alert(JSON.stringify($("#details").jsForm("get"), null, " "));
            });
        });
        </script>
    </head>
    <body>
        <h1>Simpel Form Test</h1>
        <div id="details">
            Name: <input name="data.name"/><br/>
            <input type="checkbox" name="data.active"/> active<br/>
            <textarea name="data.description"></textarea><br/>
            <select name="data.state">
                <option value="VISIBLE">visible</option>
                <option value="IMPORTANT">important</option>
                <option value="HIDDEN">hidden</option>
            </select>
            <fieldset>
                <legend>Links</legend>
                <ul class="collection" data-field="data.links">
                    <li><span class="field">links.description</span> Link: <input name="links.href"/> <button class="delete">x</button></li>
                </ul>
            </fieldset>
            <button class="add" data-field="data.links">add a link</button><br/>
            Additional field: <input name="data.addedField"/>
        </div>
        <button id="show">Show Object</button>
    </body>
</html>
avatar
serbanghita
26 апреля 2015 в 07:35
2

Я сам закодировал форму многомерного объекта JavaScript, чтобы использовать ее в производстве. Результат: https://github.com/serbanghita/formToObject.js.

Chris Baker
19 декабря 2013 в 17:35
0

Я использовал его вариант для очень конкретной реализации, большое спасибо!

Șerban Ghiță
20 декабря 2013 в 08:50
0

Спасибо, что сообщили мне, что это полезно. У меня есть несколько новых функций, и это меня мотивирует.

avatar
ngr
26 апреля 2015 в 07:33
6

Здесь лучше всего простота. Я использовал простую замену строки на регулярное выражение, и до сих пор они работали как шарм. Я не специалист по регулярным выражениям, но держу пари, что вы можете заполнять даже очень сложные объекты.

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

values.replace(/([^&]+)=([^&]*)/g, function (match, name, value) {
    attributes[name] = value;
});
avatar
xlthor
26 апреля 2015 в 07:32
-7

Используйте это:

var sf = $('#mainForm').serialize(); // URL encoded string
sf = sf.replace(/"/g, '\"');         // Be sure all "s are escaped
sf = '{"' + sf.replace(/&/g, '","'); // Start "object", replace tupel delimiter &
sf = sf.replace(/=/g, '":"') + '"}'; // Replace equal sign, add closing "object"

// Test the "object"
var formdata = eval("(" + sf + ")"); 
console.log(formdata);

Он действует как заклинание даже на очень сложные формы.

Mulan
18 февраля 2013 в 21:58
12

Вводить eval пользователем рискованно - может случиться что угодно. Настоятельно рекомендую этого не делать.

avatar
pocesar
26 апреля 2015 в 07:30
0

Мой код из моей библиотеки phery получил процедуру сериализации, которая может работать с действительно сложными формами (как в демонстрации https://github.com/pocesar/phery/blob/master/ demo.php # L1664), и это не универсальный вариант. Фактически он проверяет тип каждого поля. Например, радиоблок - это не то же самое, что диапазон, это не то же самое, что кейген, это не то же самое, что выбрать несколько. Моя функция покрывает все это, и вы можете видеть это по адресу https://github.com/pocesar/phery/blob/master/phery.js#L1851.

serializeForm:function (opt) {
    opt = $.extend({}, opt);

    if (typeof opt['disabled'] === 'undefined' || opt['disabled'] === null) {
        opt['disabled'] = false;
    }
    if (typeof opt['all'] === 'undefined' || opt['all'] === null) {
        opt['all'] = false;
    }
    if (typeof opt['empty'] === 'undefined' || opt['empty'] === null) {
        opt['empty'] = true;
    }

    var
        $form = $(this),
        result = {},
        formValues =
            $form
                .find('input,textarea,select,keygen')
                .filter(function () {
                    var ret = true;
                    if (!opt['disabled']) {
                        ret = !this.disabled;
                    }
                    return ret && $.trim(this.name);
                })
                .map(function () {
                    var
                        $this = $(this),
                        radios,
                        options,
                        value = null;

                    if ($this.is('[type="radio"]') || $this.is('[type="checkbox"]')) {
                        if ($this.is('[type="radio"]')) {
                            radios = $form.find('[type="radio"][name="' + this.name + '"]');
                            if (radios.filter('[checked]').size()) {
                                value = radios.filter('[checked]').val();
                            }
                        } else if ($this.prop('checked')) {
                            value = $this.is('[value]') ? $this.val() : 1;
                        }
                    } else if ($this.is('select')) {
                        options = $this.find('option').filter(':selected');
                        if ($this.prop('multiple')) {
                            value = options.map(function () {
                                return this.value || this.innerHTML;
                            }).get();
                        } else {
                            value = options.val();
                        }
                    } else {
                        value = $this.val();
                    }

                    return {
                        'name':this.name || null,
                        'value':value
                    };
                }).get();

    if (formValues) {
        var
            i,
            value,
            name,
            $matches,
            len,
            offset,
            j,
            fields;

        for (i = 0; i < formValues.length; i++) {
            name = formValues[i].name;
            value = formValues[i].value;

            if (!opt['all']) {
                if (value === null) {
                    continue;
                }
            } else {
                if (value === null) {
                    value = '';
                }
            }

            if (value === '' && !opt['empty']) {
                continue;
            }

            if (!name) {
                continue;
            }

            $matches = name.split(/\[/);

            len = $matches.length;

            for (j = 1; j < len; j++) {
                $matches[j] = $matches[j].replace(/\]/g, '');
            }

            fields = [];

            for (j = 0; j < len; j++) {
                if ($matches[j] || j < len - 1) {
                    fields.push($matches[j].replace("'", ''));
                }
            }

            if ($matches[len - 1] === '') {
                offset = assign_object(result, fields, [], true, false, false);

                if (value.constructor === Array) {
                    offset[0][offset[1]].concat(value);
                } else {
                    offset[0][offset[1]].push(value);
                }
            } else {
                assign_object(result, fields, value);
            }
        }
    }

    return result;
}

Это часть моей библиотеки phery , но ее можно перенести в ваш собственный проект. Он создает массивы там, где должны быть массивы, он получает правильные выбранные параметры из параметров выбора, нормализации флажка и т. Д. Если вы хотите преобразовать его в JSON (настоящая строка JSON), просто выполните JSON.stringify($('form').serializeForm());

Andrew Barber
7 декабря 2012 в 03:03
0

Stack Overflow предназначен не для того, чтобы вы продвигали свою библиотеку.

pocesar
7 декабря 2012 в 03:12
3

хорошо, но serializeForm является частью моей библиотеки и делает именно то, что хочет OP

Alex78191
11 июня 2017 в 20:56
0

Последняя строка самая лучшая

avatar
Kipras
26 апреля 2015 в 07:22
0

Это улучшение функции Тобиаса Коэна, которая хорошо работает с многомерными массивами:

http://jsfiddle.net/BNnwF/2/

Однако это не плагин jQuery, но преобразование его в него займет всего несколько секунд, если вы хотите использовать его таким образом: просто замените оболочку объявления функции:

function serializeFormObject(form)
{
    ...
}

с:

$.fn.serializeFormObject = function()
{
    var form = this;
    ...
};

Думаю, оно похоже на решение Macek в том, что оно делает то же самое, но я думаю, что это немного чище и проще. Я также включил в скрипт входные данные тестового примера Мачека и добавил несколько дополнительных. Пока что у меня это хорошо работает.

function serializeFormObject(form)
{
    function trim(str)
    {
        return str.replace(/^\s+|\s+$/g,"");
    }

    var o = {};
    var a = $(form).serializeArray();
    $.each(a, function() {
        var nameParts = this.name.split('[');
        if (nameParts.length == 1) {
            // New value is not an array - so we simply add the new
            // value to the result object
            if (o[this.name] !== undefined) {
                if (!o[this.name].push) {
                    o[this.name] = [o[this.name]];
                }
                o[this.name].push(this.value || '');
            } else {
                o[this.name] = this.value || '';
            }
        }
        else {
            // New value is an array - we need to merge it into the
            // existing result object
            $.each(nameParts, function (index) {
                nameParts[index] = this.replace(/\]$/, '');
            });

            // This $.each merges the new value in, part by part
            var arrItem = this;
            var temp = o;
            $.each(nameParts, function (index) {
                var next;
                var nextNamePart;
                if (index >= nameParts.length - 1)
                    next = arrItem.value || '';
                else {
                    nextNamePart = nameParts[index + 1];
                    if (trim(this) != '' && temp[this] !== undefined)
                        next = temp[this];
                    else {
                        if (trim(nextNamePart) == '')
                            next = [];
                        else
                            next = {};
                    }
                }

                if (trim(this) == '') {
                    temp.push(next);
                } else
                    temp[this] = next;

                temp = next;
            });
        }
    });
    return o;
}
avatar
Kevin Jhangiani
26 апреля 2015 в 07:17
0

Приведенное выше решение Тобиаса является правильным, однако, как указал комментатор @macek, оно не обрабатывает входные данные типа foo [bar] и не разделяет их на подобъекты.

Это функция только для PHP, но я по-прежнему считаю очень полезной возможность генерировать ту же структуру в JavaScript.

Я просто изменил приведенный выше код Тобиаса, так что вся заслуга принадлежит ему. Вероятно, это можно сделать чище, но я просто собрал его на скорую руку за пять минут и подумал, что это может быть полезно.

В настоящее время он не обрабатывает многомерные массивы или массивы с числовым индексом. То есть он будет работать только с именами foo [bar], но не foo [].

jQuery.fn.serializeObjectPHP = function()
{
    var o = {};
    var re = /^(.+)\[(.*)\]$/;
    var a = this.serializeArray();
    var n;
    jQuery.each(a, function() {
        var name = this.name;
        if ((n = re.exec(this.name)) && n[2]) {
            if (o[n[1]] === undefined) {
                o[n[1]] = {};
                o[n[1]][n[2]] = this.value || '';
            } else if (o[n[1]][n[2]] === undefined) {
                o[n[1]][n[2]] = this.value || '';
            } else {
                if(!o[n[1]][n[2]].push) {
                    o[n[1]][n[2]] = [ o[n[1]][n[2]] ];
                }
                o[n[1]][n[2]].push(this.value || '');
            }
        } else {
            if (n && !n[2]) {
                name = n[1];
            }
            if (o[name] !== undefined) {
                if (!o[name].push) {
                    o[name] = [o[name]];
                }
                o[name].push(this.value || '');
            } else {
                o[name] = this.value || '';
            }
        }
    });
    return o;
};
maček
22 мая 2012 в 03:32
0

похоже, что вы не прочитали весь мой комментарий. Я разработал решение, которое обрабатывает входные данные типа foo[bar], а также foo[bar][bof][a][b][c][etc]; мой ответ в этой теме. Также обратите внимание, что «синтаксический анализ» foo[bar] не является уникальным для PHP. Rails в значительной степени полагается на это соглашение для передачи атрибутов формы объектам.

avatar
Sammaye
24 апреля 2015 в 19:18
2

Я обнаружил проблему с выбранным решением.

При использовании форм с именами на основе массивов функция jQuery serializeArray () фактически умирает.

У меня есть PHP-фреймворк, который использует имена полей на основе массивов, чтобы одна и та же форма могла быть помещена на одну и ту же страницу несколько раз в нескольких представлениях. Это может быть удобно для добавления, редактирования и удаления на одной странице без конфликтующих моделей форм.

Поскольку я хотел разделить формы без необходимости убирать эту абсолютную базовую функциональность, я решил написать свой собственный seralizeArray ():

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

Обратите внимание: это также работает вне формы submit (), поэтому, если в остальной части кода возникнет ошибка, форма не будет отправлена, если вы поместите на ссылку кнопку с надписью «Сохранить изменения».

Также обратите внимание, что эту функцию никогда не следует использовать для проверки формы только для сбора данных для отправки на серверную сторону для проверки. Использование такого слабого и массового кода БУДЕТ вызывать XSS и т. Д.

avatar
17 апреля 2015 в 14:53
0

Мне пришлось бессовестно продвигать свою библиотеку форм.

transForm.js

Он выполняет следующие действия: сериализацию, десериализацию, очистку и отправку форм.

Причина, по которой я это сделал, заключается в том, что form2js / js2form не поддерживается и не такой гибкий и быстрый, как хотелось бы. Мы используем его в производстве, потому что он совместим с form2js / js2form.

avatar
6 сентября 2013 в 18:38
2

Для быстрого и современного решения используйте плагин JSONify jQuery. Пример ниже дословно взят из GitHub README. Все кредиты Кушалу Пандия, автору плагина.

Дано:

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

Работает:

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

Производит:

{"name":"Joe User","email":"joe@example.com","password":"mypass"}

Если вы хотите выполнить jQuery POST с этим объектом JSON:

$('#mybutton').click(function() {
    $.post('/api/user', JSON.stringify($('#myform').jsonify()));
}
avatar
22 июля 2013 в 09:59
294

Что не так с:

var data = {};
$(".form-selector").serializeArray().map(function(x){data[x.name] = x.value;}); 
sites
13 июня 2015 в 21:19
48

$(this).serializeArray().reduce(function(m,o){ m[o.name] = o.value; return m;}, {})

Nathan Chappell
4 августа 2021 в 12:48
0

$(this).serializeArray().reduce((o,kv) => ({...o, [kv.name]: kv.value}), {})

avatar
9 декабря 2012 в 18:47
0

Это решение лучше. Некоторые из наиболее популярных опций здесь не исправляют флажки дескрипторов, когда флажок не установлен.

       getData: function(element){
      //@todo may need additional logic for radio buttons
      var select = $(element).find('select');
      var input = $(element).find('input');
      var inputs = $.merge(select,input);
      var data = {};
      //console.log(input,'input');
      $.each(inputs,function(){
        if($(this).attr('type') != undefined){
          switch($(this).attr('type')){
            case 'checkbox':
              data[$(this).attr('name')] = ( ($(this).attr('checked') == 'checked') ? $(this).val():0 );
              break;
            default:
              data[$(this).attr('name')] = $(this).val();
              break;
          }
        }
        else{
          data[$(this).attr('name')] = $(this).val();
        }
      })
      return data;
   }
avatar
24 сентября 2012 в 19:18
16

Эта функция должна обрабатывать многомерные массивы вместе с несколькими элементами с одинаковыми именами.

Я использую его уже пару лет:

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;
};
avatar
19 апреля 2012 в 13:07
2

Превратите что-либо в объект (не тестировалось)

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

Результат теста:

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

по

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

даст:

{ input: { a: text, b: select }, otherinput: { c: { a: a, 0: b, 1: d }, d: { b: c } }, anotherinput: 1 }
{ input: { b: select } }
avatar
31 декабря 2011 в 19:34
103

Фиксированная версия решения Тобиаса Коэна. Этот правильно обрабатывает ложные значения, такие как 0 и ''.

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

И версия CoffeeScript для удобства программирования:

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
avatar
16 октября 2011 в 19:30
-1

Функция сериализации принимает объект JSON в качестве параметра и возвращает строку сериализации.

function serialize(object) {
            var _SPECIAL_CHARS = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, _CHARS = {
                '\b' : '\\b',
                '\t' : '\\t',
                '\n' : '\\n',
                '\f' : '\\f',
                '\r' : '\\r',
                '"' : '\\"',
                '\\' : '\\\\'
            }, EMPTY = '', OPEN_O = '{', CLOSE_O = '}', OPEN_A = '[', CLOSE_A = ']', COMMA = ',', COMMA_CR = ",\n", CR = "\n", COLON = ':', space = "", COLON_SP = ': ', stack = [], QUOTE = '"';
            function _char(c) {
                if (!_CHARS[c]) {
                    _CHARS[c] = '\\u' + ('0000' + (+(c.charCodeAt(0))).toString(16))
                        .slice(-4);
                }
                return _CHARS[c];
            }
            function _string(s) {
                return QUOTE + s.replace(_SPECIAL_CHARS, _char) + QUOTE;
                // return str.replace('\"','').replace('\"','');
            }

            function serialize(h, key) {
                var value = h[key], a = [], colon = ":", arr, i, keys, t, k, v;
                arr = value instanceof Array;
                stack.push(value);
                keys = value;
                i = 0;
                t = typeof value;
                switch (t) {
                    case "object" :
                        if(value==null){
                            return null;
                        }
                        break;
                    case "string" :
                        return _string(value);
                    case "number" :
                        return isFinite(value) ? value + EMPTY : NULL;
                    case "boolean" :
                        return value + EMPTY;
                    case "null" :
                        return null;
                    default :
                        return undefined;
                }
                arr = value.length === undefined ? false : true;

                if (arr) { // Array
                    for (i = value.length - 1; i >= 0; --i) {
                        a[i] = serialize(value, i) || NULL;
                    }
                }
                else { // Object
                    i = 0;
                    for (k in keys) {
                        if (keys.hasOwnProperty(k)) {
                            v = serialize(value, k);
                            if (v) {
                                a[i++] = _string(k) + colon + v;
                            }
                        }
                    }
                }

                stack.pop();
                if (space && a.length) {

                    return arr
                        ? "[" + _indent(a.join(COMMA_CR), space) + "\n]"
                        : "{\n" + _indent(a.join(COMMA_CR), space) + "\n}";
                }
                else {
                    return arr ? "[" + a.join(COMMA) + "]" : "{" + a.join(COMMA)
                        + "}";
                }
            }
            return serialize({
                "" : object
            }, "");
        }
avatar
31 марта 2011 в 21:45
29

Все эти ответы мне показались чересчур непомерными. Есть кое-что, что нужно сказать о простоте. Пока все ваши входные данные формы имеют установленный атрибут name, это должно работать, просто jim dandy.

$('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?)
});
avatar
3 марта 2011 в 13:00
6

Я обнаружил проблему с кодом Тобиаса Коэна (у меня недостаточно очков, чтобы прокомментировать его напрямую), которая в остальном работает для меня. Если у вас есть два варианта выбора с одинаковым именем, оба со значением = "", исходный код будет производить "name": "" вместо "name": ["", ""]

Я думаю, это можно исправить, добавив "|| o [this.name] == ''" к первому условию if:

$.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;
};
avatar
18 июня 2010 в 22:47
3

Я предпочитаю этот подход, потому что: вам не нужно повторять более 2 коллекций, вы можете получить другие вещи, кроме «имени» и «значения», если вам нужно, и вы можете дезинфицировать свои значения, прежде чем сохранять их в объект (например, если у вас есть значения по умолчанию, которые вы не хотите сохранять).

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

Используйте так:

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

Проверено только в Firefox.

avatar
27 июля 2009 в 03:04
0

Я бы не стал использовать это на действующем сайте из-за XSS-атак и, вероятно, множества других проблем, но вот краткий пример того, что вы можете сделать:

$("#myform").submit(function(){
    var arr = $(this).serializeArray();
    var json = "";
    jQuery.each(arr, function(){
        jQuery.each(this, function(i, val){
            if (i=="name") {
                json += '"' + val + '":';
            } else if (i=="value") {
                json += '"' + val.replace(/"/g, '\\"') + '",';
            }
        });
    });
    json = "{" + json.substring(0, json.length - 1) + "}";
    // do something with json
    return false;
});
davidtgq
27 мая 2016 в 01:16
0

Не могли бы вы обойти XSS-атаки, сначала преобразовав их в JS-объект, а не непосредственно в строку?

avatar
26 июля 2009 в 14:51
24

На самом деле нет способа сделать это без изучения каждого из элементов. Что вы действительно хотите знать, так это «написал ли кто-нибудь еще метод, преобразующий форму в объект JSON?» Что-то вроде следующего должно работать - обратите внимание, что он предоставит вам только те элементы формы, которые будут возвращены через POST (должны иметь имя). Это не тестировалось .

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