Как преобразовать все элементы моей формы в объект JavaScript?
Я хотел бы иметь способ автоматического создания объекта JavaScript из моей формы, без необходимости перебирать каждый элемент. Мне не нужна строка, возвращаемая $('#formid').serialize();
, и мне не нужна карта, возвращаемая $('#formid').serializeArray();
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;
}
Следите за скрытыми полями, которые имеют то же имя, что и реальные входы, поскольку они будут перезаписаны.
Текущий источник находится на 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();
(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);
hasOwnProperty
замечанием hasOwnProperty
)
Что случилось с:
var data = {};
$(".form-selector").serializeArray().map(function(x){data[x.name] = x.value;});
Фиксированная версия решения Тобиаса Коэна. Он правильно обрабатывает значения фальши, такие как 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 ? ''
keyMap
и следующую строку: key = if keyMap? then keyMap(@name) else @name
. Теперь вы можете передать функцию отображения как (name) -> name.match(/\[([^\]]+)]/)[1]
. И тогда нужно будет изменить все последующие @name
на key
, конечно
Мне нравится использовать 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, вам нужно использовать полифилл или другое решение в целом.
Все эти ответы казались мне слишком верными. Что-то нужно сказать для простоты. Пока все ваши входы формы имеют атрибут атрибута имени, это должно работать только джим-денди.
$('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?) });
Если вы используете Underscore.js, вы можете использовать относительно краткий:
_.object(_.map($('#myform').serializeArray(), _.values))
Невозможно сделать это без изучения каждого из элементов. То, что вы действительно хотите знать, "кто-то еще уже написал метод, который преобразует форму в объект 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;
}
Хорошо, я знаю, что у этого уже есть очень высокий ответ, но в то же время был задан еще один аналогичный вопрос, и я тоже был направлен на этот вопрос. Я также хотел бы предложить свое решение, потому что оно дает преимущество перед принятым решением: вы можете включать отключенные элементы формы (что иногда важно, в зависимости от того, как ваши функции пользовательского интерфейса)
Вот мой ответ из другого вопроса 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.
map
как это создает массив объектов с одним свойством, он не объединяет все свойства в один объект.
Эта функция должна обрабатывать многомерные массивы вместе с несколькими элементами с тем же именем.
Я использую его уже пару лет:
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;
};
Вы можете сделать это:
var frm = $(document.myform);
var data = JSON.stringify(frm.serializeArray());
См. JSON.
При всем заданном ответе есть какая-то проблема, которая...
Если введите имя как массив, например name[key]
, но он будет генерироваться так
name:{
key : value
}
Например: если у меня есть такая форма.
<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>
Затем он будет генерировать объект таким образом со всем предоставленным ответом.
Object {
name : 'value',
name1[key1] : 'value1',
name2[key2] : 'value2',
name3[key3] : 'value3',
}
Но он должен генерировать, как показано ниже, каждый хочет сделать это, как показано ниже.
Object {
name : 'value',
name1 : {
key1 : 'value1'
},
name2 : {
key2 : 'value2'
},
name3 : {
key2 : 'value2'
}
}
Затем попробуйте выполнить это ниже кода js.
(function($){
$.fn.getForm2obj = function(){
var _ = {},_t=this;
this.c = function(k,v){ eval("c = typeof "+k+";"); if(c == 'undefined') _t.b(k,v);}
this.b = function(k,v,a = 0){ if(a) eval(k+".push("+v+");"); else eval(k+"="+v+";"); };
$.map(this.serializeArray(),function(n){
if(n.name.indexOf('[') > -1 ){
var keys = n.name.match(/[a-zA-Z0-9_]+|(?=\[\])/g),le = Object.keys(keys).length,tmp = '_';
$.map(keys,function(key,i){
if(key == ''){
eval("ale = Object.keys("+tmp+").length;");
if(!ale) _t.b(tmp,'[]');
if(le == (i+1)) _t.b(tmp,"'"+n['value']+"'",1);
else _t.b(tmp += "["+ale+"]",'{}');
}else{
_t.c(tmp += "['"+key+"']",'{}');
if(le == (i+1)) _t.b(tmp,"'"+n['value']+"'");
}
});
}else _t.b("_['"+n['name']+"']","'"+n['value']+"'");
});
return _;
}
})(jQuery);
console.log($('form').getForm2obj());
<!DOCTYPE html><html><head>
<script src="/jquery-3.2.1.min.js"></script>
<title>Convert form data to JavaScript object with jQuery</title>
</head>
<body>
<form>
<input name="name" value="value" >
<input name="name1[key1]" value="value1" >
<input name="name2[key2]" value="value2" >
<input name="name3[key3]" value="value3" >
<input type="checkbox" name="name4[]" value="1" checked="checked">
<input type="checkbox" name="name4[]" value="2">
<input type="checkbox" name="name4[]" value="3">
</form>
</body></html>
Использование:
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"}
Однострочный (без зависимостей, кроме 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)
Простота здесь лучше. Я использовал замену простой строки с регулярным выражением, и до сих пор они работали как шарм. Я не специалист по регулярному выражению, но я уверен, вы даже можете заполнить очень сложные объекты.
var values = $(this).serialize(),
attributes = {};
values.replace(/([^&]+)=([^&]*)/g, function (match, name, value) {
attributes[name] = value;
});
Из более старого ответа:
$('form input, form select').toArray().reduce(function(m,e){m[e.name] = $(e).val(); return m;},{})
serializeArray
поэтому у вас есть свобода выбора любых входов, которые вы хотите (например, вы можете включить отключенные входы), верно? Т.е. это не связано с какой-либо формой или событием отправки, это просто само по себе?
reduce
возвращает объект. Это не является независимым, так как toArray
из jQuery.
Используя решение 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" />
Самый простой и самый точный способ, который я нашел для этой проблемы, - использовать плагин bbq или этот один (размер около 0,5 КБ).
он также работает с многомерными массивами.
$.fn.serializeObject = function()
{
return $.deparam(this.serialize());
};
Я нашел проблему с кодом Тобиаса Коэна (у меня недостаточно очков, чтобы прокомментировать это напрямую), что в противном случае работает для меня. Если у вас есть два варианта выбора с тем же именем, оба со значением = ", исходный код будет генерировать" имя ":" "вместо" 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;
};
Существует плагин для JQuery, jquery.serializeJSON. Я успешно использовал его в нескольких проектах. Отлично работает.
Если вы пытаетесь преобразовать все поля формы в JSON, чтобы отправить эту форму через Ajax, здесь плагин формы jQuery, который делает что.
Я сам кодировал форму для многомерного JavaScript-объекта, чтобы использовать ее в процессе производства. Результатом является /formToObject.js.
У меня была такая же проблема в последнее время и вышла с этот .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 из этого, который будет представлять эту точную структуру, чтобы вы могли:
ОК, так что теперь нам нужно подумать, как форма может представлять 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 стоит попробовать, а также тот факт, что вы можете добавлять теги ввода с одним и тем же именем, не беспокоясь, очень полезно, если вам нужно извлекать динамически созданные данные форм.
Надеюсь, это поможет кому-то!
Повернуть что-нибудь в объект (не тестировалось)
<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 } }
Я нашел проблему с выбранным решением.
При использовании форм с именами на основе массива функция 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 и т.д.
Я предпочитаю этот подход, потому что: вам не нужно перебирать более двух коллекций, вы можете получить доступ к вещам, отличным от "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.
Другой ответ
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
используя 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"
}
key[]
; [ {key: 'items[]', value: 1 }, {key: 'items[]', value: 2 } ]
приводит к { items: { "": 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":"[email protected]","password":"mypass"}
Если вы хотите сделать POST JQuery с этим объектом JSON:
$('#mybutton').click(function() {
$.post('/api/user', JSON.stringify($('#myform').jsonify()));
}
Мне нравится версия 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({data: App.toJson('#cropform: input')})
Для строкового просмотра вопроса 3593046 для скудной версии, json2.js для каждой версии, охваченной событиями. Это должно охватывать все это:)
Итак, я использовал принятый ответ и обнаружил главный недостаток.
Он не поддерживает входные массивы, такие как:
<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();
, иначе он не будет работать.
Если вы хотите преобразовать форму в объект 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
Может быть установлен с Bower: bower install git://github.com/tfmontague/form-object.git
Если вы отправляете форму с 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;
}
Я бы не использовал это на реальном сайте из-за атак 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;
});
const formData = new FormData(form);
let formDataJSON = {};
for (const [key, value] of formData.entries()) {
formDataJSON[key] = value;
}
Более современным способом является использование сокращения с помощью 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
Эта функция возвращает все значения, преобразованные в нужный тип;
bool/string/(целое число/поплавки)
Для этого вам нужно jQuery для этого, но так как serializeArray тоже jQuery, так что неважно, что это imho.
/**
* 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);
Здесь не-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;
})();
Мне приходилось бесстыдно самоподдерживать мою библиотеку форм.
Он делает такие вещи, как: сериализация, десериализация, очистка и отправка форм.
Причина, по которой я это сделал, это form2js/js2form не поддерживается и не так гибка и быстра, как хотелось бы. Мы используем его в производстве, потому что это form2js/js2form.
Недавно у меня была такая же проблема, поэтому я разработал функцию, которая позволяет анализировать элементы формы для получения идентификатора/значения управления и конвертировать его в JSON.
Он достаточно гибкий, чтобы добавлять дополнительные элементы управления. Вам просто нужно указать тип управления и атрибут, который вы хотите интерпретировать как значение.
Вы можете найти полный script здесь.
Преимущество состоит в том, что он принимает только нужные вам данные, не перетаскивая весь объект.
Недостаток заключается в том, что если у вас есть вложенные параметры, вам необходимо префикс идентификаторов соответственно, чтобы вы могли использовать дублируемую опцию для своей конкретной группы.
Надеюсь, это поможет!
Используйте $('# formName'). serializeObject()
Я написал модуль jQuery jsForm, который может делать это двунаправленным даже для довольно сложных форм (позволяет создавать коллекции и другие более сложные структуры также).
Он использует имя полей (плюс несколько специальных классов для коллекций) и соответствует объекту JSON. Он позволяет автоматическую репликацию DOM-элементов для коллекций и обработки данных:
<html>
<head>
<script src="/jquery.min.js"></script>
<script src="/jquery.jsForm.js"></script>
<script>
$(function(){
// Some JSON data
var jsonData = {
name: "TestName", // Standard inputs
description: "long Description\nMultiline", // Textarea
links: [{href:'http://stackoverflow.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>
Это решение лучше. Некоторые из наиболее популярных опций здесь не исправляют флажки, если флажок не установлен.
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;
}
Мой код из моей библиотеки phery получил процедуру сериализации, которая может обрабатывать действительно сложные формы (например, в демонстрационном https://github.com/pocesar/phery/blob/master/demo.php#L1664) и это не одноразовый. Он фактически проверяет, каков тип каждого поля. Например, радиоканал не совпадает с диапазоном, это не то же самое, что и keygen, это не то же самое, что выбрать несколько. Моя функция охватывает все это, и вы можете видеть он находится в /phery.js.
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;
}
Это часть моей библиотеки, но ее можно портировать в собственный проект. Он создает массивы, где должны быть массивы, он получает правильные выбранные параметры из параметров выбора, нормализации флажка и т.д. Если вы хотите преобразовать его в JSON (настоящую строку JSON), просто сделайте JSON.stringify($('form').serializeForm());
serializeForm
является частью моей библиотеки и делает именно то, что хочет ОП
Это улучшает функцию Тобиаса Коэна, которая хорошо работает с многомерными массивами:
Однако, это не плагин jQuery, но потребуется всего несколько секунд, чтобы сделать его одним, если вы хотите использовать его таким образом: просто замените оболочку объявления функции:
function serializeFormObject(form)
{
...
}
с:
$.fn.serializeFormObject = function()
{
var form = this;
...
};
Я думаю, это похоже на решение macek, поскольку оно делает то же самое, но я думаю, что это немного чище и проще. Я также включил входные данные теста 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;
}
Решение Tobias выше верно, однако, как заметил комментатор @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;
};
foo[bar]
а также foo[bar][bof][a][b][c][etc]
; см мой ответ в этой теме. Также обратите внимание, что foo[bar]
«синтаксический анализ» не является уникальным для PHP. Rails в значительной степени опирается на это соглашение для передачи атрибутов формы объектам.
Я не знаю, почему, но я нашел только одно действительно работающее решение для формы с входами с именами типа name="some[sub][sub][sub][name]"
.
Есть это: ССЫЛКА
Функция сериализации принимает объект 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
}, "");
}
Создайте карту и выполните цикл всех полей, сохранив их значения.
var params = {};
$("#form").find("*[name]").each(function(){
params[this.getAttribute("name")] = this.value;
});
Кто-нибудь упомянул ссылку ? довольно круто и так же просто, как $('# myform'). formParams();
Используйте это:
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);
Он работает как шарм, даже на очень сложных формах.
eval
пользовательский ввод рискованно - может случиться что угодно. Я настоятельно рекомендую не делать этого.