Comment convertir tous les éléments de mon formulaire en objet JavaScript?
J'aimerais pouvoir créer automatiquement un objet JavaScript à partir de ma fiche, sans avoir à passer en boucle sur chaque élément. Je ne veux pas de chaîne, comme retournée par $('#formid').serialize();
, ni de la carte renvoyée par $('#formid').serializeArray();
serializeArray
fait déjà exactement cela. Il vous suffit de regrouper les données dans le format requis:
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;
}
Méfiez-vous des champs cachés qui portent le même nom que les entrées réelles car ils seront écrasés.
La source de courant est sur GitHub et bower.
$ bower install jquery-serialize-object
Le code suivant peut travailler avec toutes sortes de noms d’entrée; et manipulez-les comme vous le souhaitiez.
Par exemple:
<!-- 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);
Quel est le problème avec:
var data = {};
$(".form-selector").serializeArray().map(function(x){data[x.name] = x.value;});
Une version corrigée de la solution de Tobias Cohen. Celui-ci gère correctement les valeurs de fausseté telles que 0
et ''
.
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;
};
Et une version CoffeeScript pour votre commodité de codage:
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
J'aime utiliser Array.prototype.reduce
parce que c'est un one-liner et qu'il ne repose pas sur Underscore.js ou similaire:
$('#formid').serializeArray()
.reduce(function(a, x) { a[x.name] = x.value; return a; }, {});
Ceci est similaire à la réponse utilisant Array.prototype.map
, mais vous n'avez pas besoin d'encombrer votre portée avec une variable d'objet supplémentaire. Un guichet unique.
NOTE IMPORTANTE: les formulaires dont les entrées ont des attributs name
en double sont des codes HTML valides et constituent en fait une approche commune. L'utilisation de l'une des réponses de ce fil de discussion sera inappropriée dans ce cas (puisque les clés d'objet doivent être uniques).
Toutes ces réponses me semblaient tellement excessives. Il y a quelque chose à dire pour la simplicité. Tant que toutes vos entrées de formulaire ont l'attribut name défini, cela ne devrait fonctionner que par Jim Dandy.
$('form.myform').submit(function () { var $this = $(this) , viewArr = $this.serializeArray() , view = {}; for (var i in viewArr) { view[viewArr[i].name] = viewArr[i].value; } //Do stuff with view object here (e.g. JSON.stringify?) });
Si vous utilisez Underscore.js vous pouvez utiliser le relativement concis:
_.object(_.map($('#myform').serializeArray(), _.values))
Il n’ya vraiment aucun moyen de le faire sans examiner chacun des éléments. Ce que vous voulez vraiment savoir, c'est "quelqu'un d'autre a-t-il déjà écrit une méthode qui convertit un formulaire en objet JSON?" Quelque chose comme ce qui suit devrait fonctionner - notez qu'il ne vous donnera que les éléments de formulaire qui seraient renvoyés via un POST (doit avoir un nom). Ceci est non testé .
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;
}
Ok, je sais que cela a déjà une réponse très élevée, mais une autre { une question similaire a été posée } récemment, et cette question m'a également été posée. J'aimerais également proposer ma solution, car elle offre un avantage par rapport à la solution acceptée: vous pouvez inclure des éléments de formulaire désactivés (ce qui est parfois important, selon le fonctionnement de votre interface utilisateur).
Voici ma réponse de la autre question SO }:
Initialement, nous utilisions la méthode serializeArray()
de jQuery, mais cela n'inclut pas les éléments de formulaire désactivés. Nous allons souvent désactiver les éléments de formulaire qui sont "synchronisés" avec d'autres sources sur la page, mais nous devons néanmoins inclure les données dans notre objet sérialisé. Donc, serializeArray()
est sorti. Nous avons utilisé le sélecteur :input
pour obtenir tous les éléments d'entrée (activés et désactivés) dans un conteneur donné, puis $.map()
pour créer notre objet.
var inputs = $("#container :input");
var obj = $.map(inputs, function(n, i)
{
var o = {};
o[n.name] = $(n).val();
return o;
});
console.log(obj);
Notez que pour que cela fonctionne, chacune de vos entrées aura besoin d'un attribut name
, qui sera le nom de la propriété de l'objet résultant.
C'est en fait légèrement modifié par rapport à ce que nous avons utilisé. Nous avions besoin de créer un objet structuré comme un IDictionary .NET, nous avons donc utilisé ceci: (Je le fournis ici au cas où cela serait utile)
var obj = $.map(inputs, function(n, i)
{
return { Key: n.name, Value: $(n).val() };
});
console.log(obj);
J'aime ces deux solutions, car elles constituent de simples utilisations de la fonction $.map()
et que vous avez le contrôle total sur votre sélecteur (ainsi, quels éléments vous avez fini par inclure dans l'objet résultant). En outre, aucun plugin supplémentaire requis. Plaine vieux jQuery.
Cette fonction doit gérer des tableaux multidimensionnels ainsi que plusieurs éléments portant le même nom.
Je l'utilise depuis quelques années:
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;
};
Tu peux le faire:
var frm = $(document.myform);
var data = JSON.stringify(frm.serializeArray());
Voir JSON.
Avec toutes les réponses données, il y a un problème qui est ...
Si le nom en entrée est un tableau comme name[key]
, mais cela produira comme ceci
name:{
key : value
}
Par exemple : Si j'ai forme comme ça.
<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>
Ensuite, il générera un objet comme celui-ci avec toutes les réponses données.
Object {
name : 'value',
name1[key1] : 'value1',
name2[key2] : 'value2',
name3[key3] : 'value3',
}
Mais il faut générer comme ci-dessous, tout le monde veut obtenir comme ci-dessous.
Object {
name : 'value',
name1 : {
key1 : 'value1'
},
name2 : {
key2 : 'value2'
},
name3 : {
key2 : 'value2'
}
}
Alors essayez ceci ci-dessous le code 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="https://code.jquery.com/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>
Utilisation:
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;
}
Sortie:
{"myfield": "myfield value", "passwordfield": "mypasswordvalue"}
One-Liner (pas de dépendances autres que jQuery), utilise la liaison d'objet fixe pour la fonction transmise à la méthode map
.
$('form').serializeArray().map(function(x){this[x.name] = x.value; return this;}.bind({}))[0]
Ce qu'il fait?
"id=2&value=1&comment=ok" => Object { id: "2", value: "1", comment: "ok" }
convient aux applications Web progressives (on peut facilement prendre en charge les actions de soumission de formulaire régulières ainsi que les demandes ajax)
La simplicité est la meilleure ici. J'ai utilisé une chaîne simple à remplacer par une expression régulière, et ils ont fonctionné à merveille jusqu'à présent. Je ne suis pas un expert en expression régulière, mais je parie que vous pouvez même peupler des objets très complexes.
var values = $(this).serialize(),
attributes = {};
values.replace(/([^&]+)=([^&]*)/g, function (match, name, value) {
attributes[name] = value;
});
De certains plus vieux réponse:
$('form input, form select').toArray().reduce(function(m,e){m[e.name] = $(e).val(); return m;},{})
En utilisant la solution de maček , je l'ai modifiée pour qu'elle fonctionne avec la façon dont ASP.NET MVC gère leurs objets imbriqués/complexes sur le même formulaire. Tout ce que vous avez à faire est de modifier la pièce de validation en ceci:
"validate": /^[a-zA-Z][a-zA-Z0-9_]*((?:\[(?:\d*|[a-zA-Z0-9_]+)\])*(?:\.)[a-zA-Z][a-zA-Z0-9_]*)*$/,
Cela va correspondre et ensuite mapper correctement les éléments avec des noms comme:
<input type="text" name="zooName" />
Et
<input type="text" name="zooAnimals[0].name" />
le moyen le plus simple et le plus précis que j'ai trouvé pour résoudre ce problème était d'utiliser le plugin bbq ou this one (qui fait environ 0,5 Ko).
cela fonctionne aussi avec des tableaux multi-dimensionnels.
$.fn.serializeObject = function()
{
return $.deparam(this.serialize());
};
J'ai trouvé un problème avec le code de Tobias Cohen (je n'ai pas assez de points pour le commenter directement), ce qui fonctionne normalement pour moi. Si vous avez deux options de sélection portant le même nom, les deux avec valeur = "", le code d'origine produira "nom": "" au lieu de "nom": ["", ""]
Je pense que cela peut être corrigé en ajoutant "|| o [this.name] == ''" à la première condition 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;
};
Il existe un plugin pour faire cela pour jQuery, jquery.serializeJSON. Je l'ai utilisé avec succès sur quelques projets maintenant. Il fonctionne comme un charme.
J'ai moi-même codé un formulaire dans un objet JavaScript multidimensionnel pour l'utiliser en production. Le résultat est https://github.com/serbanghita/formToObject.js .
Transformez n'importe quoi en objet (non testé par l'unité)
<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>
La sortie de test:
$(document).ready(function()
{
console.log(array.print(node.objectify($("form"), {})));
console.log(array.print(node.objectify($("form"), {selector: "select"})));
});
sur
<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>
donnera:
{ input: { a: text, b: select }, otherinput: { c: { a: a, 0: b, 1: d }, d: { b: c } }, anotherinput: 1 }
{ input: { b: select } }
J'ai eu le même problème récemment et suis sorti avec ce plugin .toJSON jQuery qui convertit un formulaire en objet JSON avec la même structure. Ceci est également particulièrement utile pour les formulaires générés dynamiquement pour lesquels vous souhaitez laisser votre utilisateur ajouter plus de champs à des emplacements spécifiques.
En réalité, vous souhaiterez peut-être créer un formulaire de manière à ce qu'il ait sa propre structure. Admettons donc que vous souhaitiez créer un formulaire dans lequel l'utilisateur insère ses lieux favoris en ville: vous pouvez imaginer que ce formulaire représente un élément XML <places>...</places>
contenant une liste de lieux que l’utilisateur aime ainsi une liste d’éléments <place>...</place>
, chacun contenant par exemple un élément <name>...</name>
, un élément <type>...</type>
, puis une liste d’éléments <activity>...</activity>
représentant les activités que vous pouvez effectuer à cet endroit. Donc, votre structure XML ressemblerait à ceci:
<places>
<place>
<name>Home</name>
<type>dwelling</type>
<activity>sleep</activity>
<activity>eat</activity>
<activity>watch TV</activity>
</place>
<place>...</place>
<place>...</place>
</places>
Ce serait génial d'avoir un objet JSON qui représenterait cette structure exacte pour que vous puissiez:
OK, nous devons maintenant réfléchir à la manière dont un formulaire peut représenter un fichier XML.
Bien sûr, la balise <form>
est la root
, mais nous avons ensuite cet élément <place>
qui est un conteneur et non un élément de données. Nous ne pouvons donc pas utiliser de balise input pour celui-ci.
Voici où la balise <fieldset>
est utile! Nous allons utiliser les balises <fieldset>
pour représenter tous les éléments de conteneur dans notre représentation sous forme/XML et obtenir ainsi un résultat comme celui-ci:
<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>
Comme vous pouvez le voir dans ce formulaire, nous enfreignons la règle des noms uniques, mais c'est correct car ils seront convertis en un tableau d'éléments, ils ne seront donc référencés que par leur index à l'intérieur du tableau.
À ce stade, vous pouvez voir qu’il n’ya pas de name="array[]"
comme le nom dans le formulaire et que tout est beau, simple et sémantique.
Maintenant, nous voulons que ce formulaire soit converti en un objet JSON qui ressemblera à ceci:
{'places':{
'place':[
{
'name': 'Home',
'type': 'dwelling',
'activity':[
'sleep',
'eat',
'watch TV'
]
},
{...},
{...}
]
}}
Pour ce faire, j'ai développé ce plugin jQuery ici que quelqu'un a aidé à optimiser dans ce Code Review thread et ressemble à ceci:
$.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;
};
J'ai aussi fait ce billet de blog pour expliquer cela plus.
Cela convertit tout le contenu d'un formulaire en JSON (même la radio et les cases à cocher) et il ne vous reste plus qu'à appeler
$.post('script.php',('form').toJSO(), ...);
Je sais qu'il existe de nombreuses façons de convertir des formulaires en objets JSON et que .serialize()
et .serializeArray()
fonctionnent très bien dans la plupart des cas et sont principalement destinés à être utilisés, mais je pense que toute cette idée de écrire un formulaire sous la forme d'une structure XML avec des noms significatifs et le convertir en un objet JSON bien formé vaut la peine d'essayer. Le fait de pouvoir ajouter des balises d'entrée du même nom sans s'inquiéter est très utile si vous avez besoin de récupérer des données de formulaire générées dynamiquement.
J'espère que ça aidera quelqu'un!
J'ai trouvé un problème avec la solution choisie.
Lors de l'utilisation de formulaires dont les noms s'appuient sur des tableaux, la fonction jQuery serializeArray () meurt.
J'ai un framework PHP qui utilise des noms de champs basés sur des tableaux pour permettre au même formulaire d'être placé sur la même page plusieurs fois dans plusieurs vues. Cela peut être pratique pour ajouter, modifier et supprimer sur la même page sans conflit de modèles de formulaire.
Puisque je voulais séraliser les formes sans avoir à supprimer cette fonctionnalité de base absolue, j'ai décidé d'écrire mon propre 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;
}
});
Remarque: ceci fonctionne également en dehors du formulaire submit (). Ainsi, si une erreur se produit dans le reste de votre code, le formulaire ne sera pas soumis si vous placez un bouton de lien disant "enregistrer les modifications".
Notez également que cette fonction ne doit jamais être utilisée pour valider le formulaire uniquement pour collecter les données à envoyer au serveur pour validation. L'utilisation d'un code aussi faible et attribué en masse provoquera XSS , etc.
Je préfère cette approche car: vous n'avez pas besoin d'itérer plus de 2 collections, vous pouvez obtenir des éléments autres que "nom" et "valeur" si nécessaire, et vous pouvez effacer vos valeurs avant de les stocker dans l'objet si vous avez des valeurs par défaut que vous ne souhaitez pas stocker, par exemple).
$.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;
}
Utilisez comme si:
var obj = $.formObject($("#someForm"));
Testé uniquement dans Firefox.
en utilisant 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"
}
J'aime la version de samuels, mais je crois qu’elle a une petite erreur. JSON est normalement envoyé en tant que
{"coreSKU": "PCGUYJS", "name_de": "peu importe", ...
Pas aussi
[{"coreSKU": "PCGUYJS"}, {"name_de": "peu importe"}, ...
alors la fonction IMO devrait se lire:
App.toJson = function( selector ) {
var o = {};
$.map( $( selector ), function( n,i )
{
o[n.name] = $(n).val();
});
return o;
}
et de l'envelopper dans un tableau de données (comme on s'y attend généralement aussi) et finalement l'envoyer sous la forme astring App.stringify ({data: App.toJson ('#cropform: input')})
Pour plus de détails, consultez Question 3593046 pour la version simplifiée, à json2.js pour la version couverte à toutes les éventualités. Cela devrait couvrir tout ça :)
Pour une solution rapide et moderne, utilisez le plugin JSONify jQuery. L'exemple ci-dessous est extrait textuellement du fichier README de GitHub. Tout crédit à Kushal Pandya, auteur du plugin.
Donné:
<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>
Fonctionnement:
$('#myform').jsonify();
Produit:
{"name":"Joe User","email":"[email protected]","password":"mypass"}
Si vous voulez faire un jQuery POST avec cet objet JSON:
$('#mybutton').click(function() {
$.post('/api/user', JSON.stringify($('#myform').jsonify()));
}
Une autre réponse
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
Je n'utiliserais pas cela sur un site actif en raison d'attaques XSS et probablement d'une foule d'autres problèmes, mais voici un exemple rapide de ce que vous pourriez faire:
$("#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;
});
Si vous envoyez un formulaire avec JSON, vous devez supprimer [] lors de l'envoi de la chaîne. Vous pouvez le faire avec la fonction 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;
}
Si vous souhaitez convertir un formulaire en un objet javascript, la solution la plus simple consiste à utiliser les méthodes each
et serializeArray
de jQuery.
$.fn.serializeObject = function() {
var form = {};
$.each($(this).serializeArray(), function (i, field) {
form[field.name] = field.value || "";
});
return form;
};
Plugin hébergé sur GitHub:
https://github.com/tfmontague/form-object/blob/master/README.md
Peut être installé avec Bower:bower install git://github.com/tfmontague/form-object.git
J'ai donc utilisé la réponse acceptée et découvert un défaut majeur.
Il ne supporte pas les tableaux d’entrée comme:
<input type="checkbox" name="array[]" value="1"/>
<input type="checkbox" name="array[]" value="2"/>
<input type="checkbox" name="array[]" value="3"/>
Ce changement mineur devrait résoudre ce problème:
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;
}
N'oubliez pas de lui transmettre le résultat de $(this).serializeArray();
sinon cela ne fonctionnera pas.
La solution ci-dessus de Tobias est la bonne, cependant, comme l'a souligné le commentateur @macek, elle ne gère pas les entrées de type foo [bar] et ne les divise pas en sous-objets.
Ceci est une fonctionnalité uniquement PHP, mais je trouve toujours très utile de pouvoir générer la même structure en JavaScript.
J'ai simplement modifié le code de Tobias ci-dessus, donc tout le mérite lui revient. Cela peut probablement être rendu plus propre, mais je viens de le préparer en cinq minutes et j'ai pensé que cela pourrait être utile.
Il ne gère pas les tableaux multidimensionnels ni les tableaux indexés numériquement pour le moment. C'est-à-dire que cela fonctionnera uniquement avec les noms foo [bar] et non 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;
};
Une méthode plus moderne consiste à utiliser réduire avec serializeArray()
de la manière suivante:
$('#formid').serializeArray()
.reduce((a, x) => ({ ...a, [x.name]: x.value }), {});
Cela aidera pour beaucoup de cas «normaux».
Pour l'instance très courante où il existe plusieurs balises avec des attributs dupliqués name
, cela ne suffit pas.
Puisque les entrées avec les attributs name
en double se trouvent normalement dans un 'wrapper' (div
, ul
, tr
, ...), comme dans cet exemple:
<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>
on peut utiliser réduire avec l'opérateur map
pour itérer sur eux:
$(".wrapperClass").map(function () {
return $(this).find('*').serializeArray()
.reduce((a, x) => ({ ...a, [x.name]: x.value }), {});
}).get();
Le résultat sera un tableau d'objets au format:
[
{
one: valueOfOne,
two: valueOfTwo
}, {
one: valueOfOne,
two: valueOfTwo
}
]
L'opérateur .get()
est utilisé avec map
pour obtenir le tableau de base à la place de l'objet jQuery qui donne un résultat plus propre. Documents jQuery
Cette solution est meilleure. Certaines des options les plus populaires ici ne corrigent pas les cases à cocher des poignées lorsque cette case n'est pas cochée.
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;
}
Mon code de ma bibliothèque phery dispose d'une routine de sérialisation pouvant traiter des formulaires très complexes (comme dans la démo https://github.com/pocesar/phery/blob/master/demo.php#L1664 ), et ce n’est pas un modèle unique. Il vérifie en réalité le type de chaque champ. Par exemple, une boîte radio n’est pas la même chose qu’une plage, ce n’est pas la même chose que keygen, ce n’est pas la même chose que sélectionner plusieurs. Ma fonction couvre tout cela et vous pouvez voirit à https://github.com/pocesar/phery/blob/master/phery.js#L1851 .
serializeForm:function (opt) {
opt = $.extend({}, opt);
if (typeof opt['disabled'] === 'undefined' || opt['disabled'] === null) {
opt['disabled'] = false;
}
if (typeof opt['all'] === 'undefined' || opt['all'] === null) {
opt['all'] = false;
}
if (typeof opt['empty'] === 'undefined' || opt['empty'] === null) {
opt['empty'] = true;
}
var
$form = $(this),
result = {},
formValues =
$form
.find('input,textarea,select,keygen')
.filter(function () {
var ret = true;
if (!opt['disabled']) {
ret = !this.disabled;
}
return ret && $.trim(this.name);
})
.map(function () {
var
$this = $(this),
radios,
options,
value = null;
if ($this.is('[type="radio"]') || $this.is('[type="checkbox"]')) {
if ($this.is('[type="radio"]')) {
radios = $form.find('[type="radio"][name="' + this.name + '"]');
if (radios.filter('[checked]').size()) {
value = radios.filter('[checked]').val();
}
} else if ($this.prop('checked')) {
value = $this.is('[value]') ? $this.val() : 1;
}
} else if ($this.is('select')) {
options = $this.find('option').filter(':selected');
if ($this.prop('multiple')) {
value = options.map(function () {
return this.value || this.innerHTML;
}).get();
} else {
value = options.val();
}
} else {
value = $this.val();
}
return {
'name':this.name || null,
'value':value
};
}).get();
if (formValues) {
var
i,
value,
name,
$matches,
len,
offset,
j,
fields;
for (i = 0; i < formValues.length; i++) {
name = formValues[i].name;
value = formValues[i].value;
if (!opt['all']) {
if (value === null) {
continue;
}
} else {
if (value === null) {
value = '';
}
}
if (value === '' && !opt['empty']) {
continue;
}
if (!name) {
continue;
}
$matches = name.split(/\[/);
len = $matches.length;
for (j = 1; j < len; j++) {
$matches[j] = $matches[j].replace(/\]/g, '');
}
fields = [];
for (j = 0; j < len; j++) {
if ($matches[j] || j < len - 1) {
fields.Push($matches[j].replace("'", ''));
}
}
if ($matches[len - 1] === '') {
offset = assign_object(result, fields, [], true, false, false);
if (value.constructor === Array) {
offset[0][offset[1]].concat(value);
} else {
offset[0][offset[1]].Push(value);
}
} else {
assign_object(result, fields, value);
}
}
}
return result;
}
Cela fait partie de ma bibliothèque phery, mais il peut être porté sur votre propre projet. Il crée des tableaux où il devrait y en avoir, il obtient les options sélectionnées correctes dans les options de sélection, de normalisation, etc. Si vous voulez le convertir en JSON (une vraie chaîne JSON), faites simplement JSON.stringify($('form').serializeForm());
.
const formData = new FormData(form);
let formDataJSON = {};
for (const [key, value] of formData.entries()) {
formDataJSON[key] = value;
}
Cela améliore la fonction de Tobias Cohen, qui fonctionne bien avec les tableaux multidimensionnels:
Cependant, ce n'est pas un plugin jQuery, mais cela ne prendra que quelques secondes pour en faire un si vous souhaitez l'utiliser de cette façon: remplacez simplement le wrapper de déclaration de fonction:
function serializeFormObject(form)
{
...
}
avec:
$.fn.serializeFormObject = function()
{
var form = this;
...
};
Je suppose que cela ressemble à la solution de macek en ce sens qu’il fait la même chose, mais je pense que c’est un peu plus propre et plus simple. J'ai également inclus les entrées de cas de test de macek dans le violon et en ai ajouté d'autres. Jusqu'ici cela fonctionne bien pour moi.
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;
}
J'ai récemment eu le même problème, j'ai donc développé une fonction qui permet d'analyser les contrôles d'un formulaire pour obtenir le contrôle id/value et le convertir en JSON.
Il est suffisamment souple pour permettre d’ajouter plus de contrôles. Il vous suffit de spécifier le type de contrôle et l'attribut que vous souhaitez interpréter en tant que valeur.
Vous pouvez trouver le script complet ici .
L'avantage est qu'il ne prend que les données dont vous avez réellement besoin, sans faire glisser l'objet entier.
Le désavantage est que si vous avez des options imbriquées, vous devez préfixer les ID en conséquence afin de pouvoir utiliser une option en double pour son groupe spécifique.
J'espère que ça aide!
Voici une manière non 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';
});
Vous pouvez l'utiliser comme ceci:
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;
})();
La fonction serialize prend un objet JSON en tant que paramètre et renvoie serialize String.
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
}, "");
}
J'ai dû promouvoir moi-même ma bibliothèque de formulaires sans vergogne.
Il fait des choses comme: sérialiser, désérialiser, effacer et soumettre des formulaires.
La raison pour laquelle j’ai fait ceci est form2js/js2form n’est pas maintenue et n’est pas aussi flexible et rapide que je l’aimerais. Nous l'utilisons en production car il est compatible form2js/js2form.
J'ai écrit un module jQuery, jsForm , qui peut le faire de manière bidirectionnelle même pour des formulaires assez compliqués (autorise les collections et d'autres structures plus complexes).
Il utilise le nom des champs (plus quelques classes spéciales pour les collections) et correspond à un objet JSON. Il permet la réplication automatique des éléments DOM pour les collections et le traitement des données:
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://raw.github.com/corinis/jsForm/master/src/jquery.jsForm.js"></script>
<script>
$(function(){
// Some JSON data
var jsonData = {
name: "TestName", // Standard inputs
description: "long Description\nMultiline", // Textarea
links: [{href:'http://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>