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

1625

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

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

Yisroel
источник
16
потому что первый возвращает строку, точно так же, как если бы вы отправили форму с помощью метода GET, а второй - массив объектов, каждый из которых имеет пару имя-значение. Я хочу, чтобы, если у меня было поле с именем «email», я получал объект, который позволит мне получить это значение с помощью obj.email. С serializeArray () мне нужно было бы сделать что-то вроде obj [indexOfElement] .value
Исроэль
2
@James - Принятый ответ с использованием библиотеки Д. Крокфорда JSON-js. Вот пример: github.com/tleese22/google-app-engine-jappstart/blob/master/src/…
Тейлор Лиз,
4
@ Тейлор Да, я бы сказал, что в правильном ответе используется функция Крокфорда «lib» и «Tobias», например: JSON.stringify ($ ('myForm'). SerializeObject ())
Джеймс МакКормак,
5
@Jonz - Есть и другие причины, кроме отправки / передачи для использования элемента формы. Если вы выполняете тяжелую работу со значениями форм в JavaScript (например, одностраничное приложение), очень удобно иметь их в объектном формате для доступа и манипулирования ими. Кроме того, строки запросов HTTP Post и Get - не единственные форматы для перемещения данных.
Патрик М
3
Хороший js, с которым я столкнулся >> github.com/marioizquierdo/jquery.serializeJSON
Бонги

Ответы:

1657

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

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

Тобиас Коэн
источник
4
как говорит tvanfosson, зачем повторять коллекцию дважды?
Исроэль
69
Вы имеете в виду "зачем использовать serializeArray для получения данных?" Поскольку serializeArray уже написан, он тестируется в нескольких браузерах и теоретически может быть улучшен в более поздних версиях jQuery. Чем меньше кода, который вы пишете для прямого доступа к несовместимым элементам, таким как элементы DOM, тем стабильнее будет ваш код.
Тобиас Коэн
56
Имейте в виду, что serializeArray () не будет включать отключенные элементы. Я часто отключаю элементы ввода, которые синхронизируются с другими элементами на странице, но я все же хочу, чтобы они были включены в мой сериализованный объект. Вам лучше использовать что-то вроде, $.map( $("#container :input"), function(n, i) { /* n.name and $(n).val() */ } );если вам нужно включить отключенные элементы.
Самуэль Мичам
22
@TobiasCohen Он не обрабатывает foo[bar]входные данные -типа, как ожидалось, не говоря уже о большинстве других разновидностей входных имен. Будучи очень разочарованным мелкими решениями этой проблемы, я закончил тем, что написал свой собственный плагин jQuery - подробности в ответе, который я предоставил на этот вопрос.
Мачек
6
@macek Я знаю, что это несколько месяцев, но с каких пор массивы используют нечисловые индексы? Никто не должен называть входные данные foo [bar] и надеяться рассматривать их как массив. Вы путаете массивы и хэши? Да, [] обычно понимается как метод доступа, но не только для массивов. Также говорят, что это действительный HTML, но не в спецификации HTML, противоречие. Да, браузер может не подавиться им, но не многие веб-серверы будут знать, как десериализовать это, как если бы они были массивом. Почему? Потому что его нет в спецификации HTML. Следовательно, это действительно недействительно.
Крёре
446

Конвертировать формы в 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);
maček
источник
17
Итак, это работает довольно хорошо. Но он ошибочно назван: он не возвращает JSON, как следует из названия. Вместо этого он возвращает объектный литерал. Кроме того, важно проверить наличие hasOwnProperty, в противном случае в ваших массивах есть все, что связано с их прототипом, например: {numbers: ["1", "3", indexOf: function () {...}]}
frontendbeauty,
5
@frontendbeauty на самом деле, toJSON - это именно то, что в спецификации сказано, что его следует называть: developer.mozilla.org/en/JSON#toJSON()_method - неудачный неверный номер.
Райан Флоренс
4
@ Марек, я проверил здесь на jsfiddle . Хитрость заключается в том, чтобы правильно назвать ваш выбор. <select name="foo" multiple="multiple">не будет работать в любом сценарии. Однако, если вы используете [], как в <select name="bar[]" multiple="multiple">, он будет работать просто отлично :)
maček
3
Хотел бы отметить, что github.com/serbanghita/formToObject - это аналогичный метод JavaScript (сторонние библиотеки не нужны), который выполняет ту же работу. Поддерживает «несколько», игнорирует «отключенные» элементы.
Шербан Гицэ
8
Это решение должно быть на вершине, так как оно касается проблемы вложенных ключей как имен элементов формы.
SquareCat
283

Что случилось с:

var data = {};
$(".form-selector").serializeArray().map(function(x){data[x.name] = x.value;}); 
mkschreder
источник
2
@LayZee - если ничего не выбрано, зачем вам это на заднем плане? если вы должны выбрать опцию, проверьте ввод перед сериализацией.
Дементик,
21
если вы ничего не возвращаете, почему бы вам просто не использовать .eachвместо .map??
Азерафати
10
Это так просто, потому что это супер наивно ... не обрабатывает флажки с тем же именем. Каждый раз он будет перезаписывать проверенный элемент перед ним. Вам определенно понадобится некоторое определение типа входа, чтобы убедиться, что он правильно сериализован.
Джошуа Ф. Раунтри
5
Если вам нужно чистое решение jQuery, вы можете использоватьvar 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;}, {})
сайты
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
Даниэль Х Мур
источник
В coffeescript, что первый блок if может быть сокращен доvalue = @value ? ''
nzifnab
И если вы пытаетесь сериализовать Rails-подобные формы, вы можете удалить элемент root из сгенерированных ключей. Чтобы достичь этого, я добавил новый параметр keyMapи следующую строку: key = if keyMap? then keyMap(@name) else @name. Теперь вы можете передать функцию отображения, как (name) -> name.match(/\[([^\]]+)]/)[1]. И тогда можно было бы необходимо изменить все последующие @nameдо key, конечно
Дамир Zekić
@ DamirZekić, если у вас есть корневой элемент post, вы можете просто сделать $('form').serializeObject().post. Нет необходимости в фантазии карт.
Мачек
@ DamirZekić Что делает эта линия? if (!objectData[this.name].push)??
Китту
@kittu Проверяет, objectData[this.name]есть ли метод push (грубо говоря, массив). Если это массив, он выталкивает значение, если это не массив, он преобразует его в массив, так что несколько значений с одним и тем же ключом будут объединены в массив.
Даниэль Х Мур
63

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

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

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

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

Ethan Brown
источник
Это довольно элегантно. Но стоит отметить, что array.prototype.reduce()он недоступен в IE8, поскольку он является частью спецификации ECMAScript 5. Так что, если вам нужна поддержка IE8, вы захотите использовать полифилл или другое решение в целом.
Gfullam
3
Правда, но это достаточно легко, чтобы заполнить. Кроме того, головная боль IE8 почти прекратилась благодаря великолепной работе Microsoft с IE11 Enterprise Mode - я больше не обслуживаю отдельных пользователей с IE8, но когда приходит организация с 10000 сотрудников, которые все используют IE8 ... это другое. К счастью, Microsoft усердно работает над этой проблемой.
Итан Браун
1
Что ж, вам нужно, чтобы ваши ИТ-специалисты посмотрели на IE11 Enterprise mode - он предоставляет современный браузер И способ запуска IE8-совместимых приложений. Умный ход со стороны Microsoft: howtogeek.com/184634/…
Итан Браун
30

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

$('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?)
});
Джеффри Ван Алстайн
источник
4
Однако не обрабатывает данные вложенных форм, поэтому ответы становятся более сложными.
frontendbeauty
Отлично сработало для меня. Просто необходимо хранение пар ключ-значение; Стригизация, а затем сохранение в localStorage или в cookie-файлы работали просто великолепно.
Грег Петтит
23

Там действительно нет способа сделать это без изучения каждого из элементов. Что вы действительно хотите знать, так это «кто-то другой уже написал метод, который преобразует форму в объект 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;
}
tvanfosson
источник
правда, я хотел бы плагин, который сделал бы это для меня. ограничение имени не имеет большого значения. будет ли это тянуть все поля в форме, включая textareas и select?
Исроэль
Не уверен, что вы хотите, чтобы учесть [отключено], но я не думаю, что это следует отправить / забрать.
meder omuraliev
может быть проще использовать serializeArray () для получения карты, а затем использовать код, аналогичный приведенному выше, для преобразования его в обычный объект JSON, так что я не имею дело с самой формой
Yisroel
2
Использование serializedArray будет работать, но по сути вы будете выполнять итерацию по коллекции дважды: один раз для создания массива, затем для массива. Я не вижу в этом необходимости.
tvanfosson
Я настрою селектор для включения / выключения.
tvanfosson
23

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

_.object(_.map($('#myform').serializeArray(), _.values))
olleicua
источник
19

Я проверил, что есть проблема со всеми другими ответами, что если входное имя в виде массива, например 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>

Bhavik Hirani
источник
Этот ответ охватывает упомянутый случай, но он не охватывает такие случаи, как флажок [] или даже один [другой] [another_one]
Леонардо Бил
1
@ LeonardoBeal я исправляю свои ответы .. проверь это сейчас ..!
Бхавик Хирани
Я - отрицатель, и я понизил голос, потому что evalне должен использоваться таким образом, потому что eval, при использовании таким образом, продвигает ужасно ненадежные, ошибочные, плохо работающие и потенциально небезопасные методы.
Джек Гиффин
2
Я не могу согласиться, что это хороший ответ. И, пожалуйста, когда вы пишете ответы, сделайте код понятным или объясните это. this.c = function(k,v){ eval("c = typeof "+k+";"); if(c == 'undefined') _t.b(k,v);}является кратким и не объясняющим. Разработчик с меньшим опытом просто скопирует это, не понимая, почему и как это работает.
iRaS
2
@JackGiffin Проверьте мой новый код сейчас, потому что я удалил eval()из своего кода.
Бхавик Хирани
17

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

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

Изначально мы использовали serializeArray()метод jQuery , но он не включает отключенные элементы формы. Мы часто отключаем элементы формы, которые «синхронизируются» с другими источниками на странице, но нам все равно необходимо включить данные в наш сериализованный объект. Так 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.

Самуэль Мичам
источник
6
Я пробовал это в проекте, используя, mapкак это создает массив объектов с одним свойством, он не объединяет все свойства в один объект.
Джошперри
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;
};
Сергей Варламов
источник
15

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

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

Смотрите JSON .

Harini Sekar
источник
14

Однострочный (без зависимостей, кроме 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)

test30
источник
12

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

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"}
Adrian Seeley
источник
7

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

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

values.replace(/([^&]+)=([^&]*)/g, function (match, name, value) {
    attributes[name] = value;
});
нгр
источник
7

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

$('form input, form select').toArray().reduce(function(m,e){m[e.name] = $(e).val(); return m;},{})
juanpastas
источник
Из того, что я могу сказать, разница в том, что ваше решение не зависит от serializeArrayвас, поэтому у вас есть свобода выбора любых входов, которые вы хотите (например, вы можете включить отключенные входы), верно? Т.е. это не связано с какой-либо формой или событием отправки, это просто само по себе?
января
единственная небольшая разница со связанным ответом состоит в том, что нет никаких данных, необходимых для создания экземпляра, reduceвозвращает объект. Это не является независимым, так toArrayкак от jQuery.
сайты
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;
};
user1134789
источник
6

Используя решение Мачека , я изменил его, чтобы он работал так, как 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" />
G-Ram
источник
5

самый простой и точный способ я нашел для этой проблемы заключается в использовании барбекю плагин или это один (что составляет около 0.5K байт размера).

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

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

Roey
источник
Это, кажется, работает хорошо. Есть альтернативный репозиторий для jquery-deparam, который включает в себя файлы описания для bower и npm.
Альф Итон
4

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

Peter Mortensen
источник
4
const formData = new FormData(form);

let formDataJSON = {};

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

    formDataJSON[key] = value;
}
Stonetip
источник
3

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

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

kflorence
источник
3

Превратите что-нибудь в объект (не проверенный на предмет юнитов)

<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 } }
eithed
источник
3

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

При использовании форм с именами на основе массива функция 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 и т. Д.

Sammaye
источник
3

В последнее время у меня возникла та же проблема, и я выпустил этот плагин .toJSON jQuery, который преобразует форму в объект 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, который кто-то помог оптимизировать в этой ветке Code Review, и выглядит так:

$.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
источник
Что ты пытаешься сделать?
Onheiron
3

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

serbanghita
источник
Я использовал вариант этого для очень конкретной реализации, большое спасибо!
Крис Бейкер
Спасибо, что сообщили мне, что это полезно. У меня есть некоторые входящие функции, чтобы катиться, и это мотивирует меня.
Șerban Ghiță
3

Другой ответ

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
источник
3

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

С простым oneliner в ванили JS:

Object.fromEntries(new FormData(form))
Арет
источник
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;
}

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

Для stringify взгляда на вопросе 3593046 ненасыщенной версию, в json2.js для каждых-неожиданностей покрытой версии. Это должно покрыть все это :)

Фрэнк Ноке
источник
Спасибо .. это делает (как вы упомянули) крошечную, но очень важную разницу.
Адарша,
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()));
}
Джим Стюарт
источник