Перетворення даних форми в об’єкт JavaScript за допомогою jQuery


1624

Як конвертувати всі елементи форми в об’єкт JavaScript?

Я хотів би мати якийсь спосіб автоматичного побудови об’єкта JavaScript з моєї форми, не потребуючи перекидання на кожен елемент. Я не хочу рядок, як повернуто $('#formid').serialize();, ні я не хочу повертати карту$('#formid').serializeArray();


16
тому що перший повертає рядок, точно так само, як ви отримали, якби ви подали форму методом GET, а другий дає вам масив об'єктів, кожен з яких має пару значень імен. Я хочу, щоб у мене було поле з назвою "email", я отримав об'єкт, який дозволить мені отримати це значення за допомогою obj.email. З serializeArray (), я повинен був би зробити що - щось на зразок OBJ [indexOfElement] .value
Ісроель

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

4
@Taylor Так, я б сказав, що правильна відповідь використовує функцію lib та Tobias Crockford так: JSON.stringify ($ ('myForm'). SerializeObject ())
Джеймс Маккормак

5
@Jonz - Є й інші причини, крім подання / передачі для використання елемента форми. Якщо ви робите важкий підйом зі значеннями форм у JavaScript (наприклад, програма для однієї сторінки), дуже зручно мати їх у об'єктному форматі для доступу та маніпулювання. Крім того, рядки запитів HTTP Post and 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 - деталі у відповіді, яку я надав на це питання.
maček

6
@macek Я знаю, що це вже кілька місяців, але з тих пір, коли масиви використовують нечислові індекси? Ніхто не повинен називати вхідний foo [bar] і сподіватися трактувати його як масив. Ви плутаєте масиви та хеші? Так, [] прийнято розуміти як аксесуар, але не лише для масивів. Також твердження, що це дійсний HTML, але не в специфікації HTML, є суперечливістю. Так, веб-переглядач може не задихатися, але не багато веб-серверів знають, як десеріалізувати це, як би вони мали масив. Чому? Тому що його немає в специфікації HTML. Тому він дійсно недійсний.
kroehre

446

Перетворюйте форми в JSON як бос


Джерело струму знаходиться на GitHub та Bower .

$ bower встановити 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);

17
Отже, це працює досить добре. Але це неправильно названо: він не повертає JSON, як випливає з назви. Натомість він повертає об'єкт буквально. Також важливо перевірити наявність hasOwnProperty, інакше у ваших масивах є все, що додається до їхнього прототипу, наприклад: {numbers: ["1", "3", indexOf: function () {...}]}
frontendbeauty

5
@frontendbeauty насправді, toJSON - саме те, що специфікація каже, що його слід називати: developer.mozilla.org/en/JSON#toJSON()_method нещасний помилок.
Райан Флоренція

4
@Marek, я зробив тут тест на jsfiddle . Хитрість полягає в тому, щоб правильно назвати свій вибір. <select name="foo" multiple="multiple">не працюватиме за жодного сценарію. Однак якщо ви користуєтесь [], як в <select name="bar[]" multiple="multiple">, це буде добре працювати :)
maček

3
Хотіли зазначити, що github.com/serbanghita/formToObject - це аналогічний метод JavaScript (не потрібні сторонні бібліотеки), який виконує ту саму роботу. Підтримує "кілька", ігнорує "відключені" елементи.
Șerban Ghiță

8
Це рішення повинно бути зверху, оскільки воно стосується проблеми вкладених ключів як імен елементів форми.
SquareCat

283

Що не так з:

var data = {};
$(".form-selector").serializeArray().map(function(x){data[x.name] = x.value;}); 

2
@LayZee - якщо нічого не вибрано, чому б ви хотіли це зробити на зворотному боці? якщо потрібно вибрати параметр, перевірити введення даних перед серіалізацією.
Дементік

21
якщо ви нічого не повертаєте, чому б просто не використати .eachзамість .map??
azerafati

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

У кофескрипті, що перший, якщо блок можна буде скоротити доvalue = @value ? ''
nzifnab

І якщо ви намагаєтеся серіалізувати форми, схожі на Rails, можливо, ви захочете видалити корінь елемента із створених ключів. Щоб досягти цього, я додав новий параметр keyMapі наступний рядок: key = if keyMap? then keyMap(@name) else @name. Тепер ви можете передавати функцію відображення на зразок (name) -> name.match(/\[([^\]]+)]/)[1]. І тоді можна було б необхідно змінити всі наступні @nameдо key, звичайно
Дамір Zekić

@ DamirZekić, якби ваш кореневий елемент був post, ви могли просто зробити $('form').serializeObject().post. Не потрібно фантазійного картографування.
maček

@ DamirZekić Що робить ця лінія? if (!objectData[this.name].push)??
kittu

@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, і це фактично загальний підхід. Використання будь-якого з відповідей у ​​цьому потоці буде недоцільним у такому випадку (оскільки об’єктні ключі повинні бути унікальними).


Це досить елегантно. Але варто зазначити, що array.prototype.reduce()він недоступний в IE8, оскільки він є частиною специфікації ECMAScript 5. Тож якщо вам потрібна підтримка IE8, ви хочете взагалі використовувати поліфункцію чи інше рішення.
gfullam

3
Щоправда, але це досить просто для заповнення. Крім того, головний біль IE8 майже закінчився, завдяки чудовій роботі Microsoft з IE11 Enterprise Mode - я більше не задовольняю окремих користувачів з IE8, але коли організація з 10 000 співробітників, які всі користуються IE8, приходить разом ... це різне. На щастя, Microsoft наполегливо працює над цією проблемою.
Етан Браун

1
Добре, щоб ваші ІТ-люди намагалися переглядати режим IE11 Enterprise - це сучасний браузер І спосіб запускати 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;
}

правда, я б хотів плагін, який зробив би це для мене. обмеження наявності імені - це не велика справа. це потягне всі поля у форму, включаючи текстові області та вибрані?
Yisroel

не впевнений, чи хочете ви взяти на облік [відключений], але я не думаю, що його слід надсилати / брати.
meder omuraliev

може бути простіше використовувати serializeArray (), щоб отримати карту, а потім використовувати код, подібний до вище, щоб перетворити його в звичайний об’єкт JSON, таким чином я не маю справу з самою формою
Yisroel

2
Використання serializedArray спрацювало б, але, по суті, ви б повторювали колекцію двічі - один раз для створення масиву, а потім над масивом. Я не бачу потреби в цьому.
tvanfosson

Я відрегулюю селектор для включеного / відключеного.
tvanfosson

23

Якщо ви використовуєте Underscore.js, ви можете використовувати відносно стислі:

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

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>


Ця відповідь охоплює згаданий випадок, але він не охоплює випадки, як прапорець [] або навіть один [інший] [інший_он]
Леонардо Біл

1
@LeonardoBeal я виправляю анс .. перевірити це зараз ..!
Bhavik Hirani

Я є прихильником, і я прихильнився тому, що evalйого не слід застосовувати таким чином, оскільки eval, використовуючи таким чином, рекламує жахливо ненадійні, баггі, неефективні та потенційно незахищені практики.
Джек Гіффін

2
Я не можу погодитися, що це хороша відповідь. І будь ласка, коли ви пишете відповіді, зробіть свій код самостійним поясненням або поясніть його. this.c = function(k,v){ eval("c = typeof "+k+";"); if(c == 'undefined') _t.b(k,v);}короткий і не пояснювальний. Розробник з меншим досвідом просто скопіює це, не розуміючи, чому і як це працює.
iRaS

2
@JackGiffin Ознайомтесь з моїм новим кодом зараз, оскільки я видалив його eval()з коду.
Bhavik Hirani

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як це створює масив об'єктів з однією властивістю, він не згортає всі властивості в один об'єкт.
joshperry

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


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)


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

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

З того, що я можу сказати, різниця полягає в тому, що ваше рішення не залежить від serializeArrayтого, що ви маєте свободу вибирати будь-які вхідні дані (наприклад, ви можете включити ввімкнені вводи), правда? Тобто це не пов'язано з будь-якою формою або подією подання, вона просто незалежна сама по собі?
двтан

Єдина невелика різниця із пов'язаною відповіддю полягає в тому, що немає даних, необхідних для інстанції, reduceповертає об'єкт. Це не є незалежним, оскільки toArrayце від jQuery.
сайти

6

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

Я думаю, що це можна виправити, додавши "|| o [this.name] == ''" до першого, якщо умова:

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

6

Використовуючи рішення 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" />

5

найпростіший і точний спосіб я знайшов для цієї проблеми полягає у використанні барбекю плагін або це один (що становить близько 0.5K байт розміру).

він також працює з багатовимірними масивами.

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


Це, здається, працює добре. Є альтернативне сховище для jquery-deparam, що включає файли опису для bower та npm.
Альф Ітон


4
const formData = new FormData(form);

let formDataJSON = {};

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

    formDataJSON[key] = value;
}

3

Я віддаю перевагу такому підходу, оскільки: вам не потрібно повторювати дві колекції, ви можете отримати інші речі, крім "ім'я" та "значення", якщо вам потрібно, і ви можете санітувати свої цінності, перш ніж зберігати їх в об'єкті ( якщо у вас є значення за замовчуванням, які ви не бажаєте зберігати, наприклад).

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


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

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 тощо.


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-файл (навіть якщо ви не знаєте його точної структури a-priori)
  • Просто якимось чином використовуйте його таким, яким він є у будь-якому сценарії сервера, подібного до 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 тут, який хтось допоміг оптимізувати у цій темі перегляду коду і виглядає так:

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

3

Я зашифрував форму для багатовимірного об’єкта JavaScript, щоб використовувати його у виробництві. Результат - https://github.com/serbanghita/formToObject.js .


Я використовував варіацію цього для дуже конкретної реалізації, велике спасибі!
Кріс Бейкер

Дякуємо, що повідомили мені, що це корисно. У мене є деякі функції, що надходять, і це мене мотивує.
banerban 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


3

[ОНОВЛЕННЯ 2020]

За допомогою простого лінійки ванілі 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 App.stringify ({data: App.toJson ('#cropform: input')})

Щоб детальніше подивитись на питання 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()));
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.