Konvertieren Sie Formulardaten mit jQuery in ein JavaScript-Objekt

1624

Wie konvertiere ich alle Elemente meines Formulars in ein JavaScript-Objekt?

Ich möchte eine Möglichkeit haben, automatisch ein JavaScript-Objekt aus meinem Formular zu erstellen, ohne jedes Element durchlaufen zu müssen. Ich möchte weder eine Zeichenfolge, wie von zurückgegeben $('#formid').serialize();, noch möchte ich, dass die Karte von zurückgegeben wird$('#formid').serializeArray();

Yisroel
quelle
16
weil der erste eine Zeichenfolge zurückgibt, genau wie Sie ihn erhalten würden, wenn Sie das Formular mit einer GET-Methode senden würden, und der zweite eine Reihe von Objekten mit jeweils einem Name-Wert-Paar enthält. Ich möchte, dass ich, wenn ich ein Feld mit dem Namen "email" habe, ein Objekt erhalte, mit dem ich diesen Wert mit obj.email abrufen kann. Mit serializeArray () müsste ich so etwas wie obj [indexOfElement] .value
Yisroel
2
@James - Die akzeptierte Antwort unter Verwendung der JSON-js-Bibliothek von D. Crockford. Hier ist ein Beispiel: github.com/tleese22/google-app-engine-jappstart/blob/master/src/…
Taylor Leese
4
@ Taylor Ja, ich würde sagen, die richtige Antwort verwendet Crockfords lib und Tobias 'Funktion wie folgt: JSON.stringify ($ (' myForm '). SerializeObject ())
James McCormack
5
@Jonz - Neben der Übermittlung / Übertragung gibt es noch andere Gründe für die Verwendung eines Formularelements. Wenn Sie mit den Formularwerten in JavaScript (z. B. App für einzelne Seiten) viel zu tun haben, ist es sehr praktisch, sie in einem Objektformat für den Zugriff und die Bearbeitung zu haben. Außerdem sind HTTP Post and Get-Abfragezeichenfolgen nicht die einzigen Formate zum Verschieben von Daten.
Patrick M
3
Ein gutes js Ich bin auf >> github.com/marioizquierdo/jquery.serializeJSON
Bongs

Antworten:

1657

serializeArraymacht schon genau das. Sie müssen nur die Daten in das gewünschte Format einmassieren:

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

Achten Sie auf versteckte Felder, die denselben Namen wie echte Eingaben haben, da diese überschrieben werden.

Tobias Cohen
quelle
4
Wie tvanfosson sagt, warum zweimal über die Sammlung iterieren?
Yisroel
69
Meinen Sie "warum sollten Sie serializeArray verwenden, um die Daten überhaupt abzurufen?" Da serializeArray bereits geschrieben wurde, in mehreren Browsern getestet wurde und theoretisch in späteren Versionen von jQuery verbessert werden könnte. Je weniger Code Sie schreiben, um direkt auf inkonsistente Elemente wie DOM-Elemente zugreifen zu können, desto stabiler ist Ihr Code.
Tobias Cohen
56
Seien Sie gewarnt, serializeArray () enthält keine deaktivierten Elemente. Ich deaktiviere häufig Eingabeelemente, die mit anderen Elementen auf der Seite synchronisiert werden, möchte sie jedoch weiterhin in meinem serialisierten Objekt enthalten. Verwenden Sie besser etwas, $.map( $("#container :input"), function(n, i) { /* n.name and $(n).val() */ } );wenn Sie deaktivierte Elemente einschließen müssen.
Samuel Meacham
22
@TobiasCohen Es werden foo[bar]Eingaben vom Typ "Typ" nicht wie erwartet verarbeitet, ganz zu schweigen von den meisten anderen Arten von Eingabenamen. Nachdem ich mit flachen Lösungen für dieses Problem sehr frustriert war, schrieb ich mein eigenes jQuery-Plugin - Details in der Antwort, die ich auf diese Frage gegeben habe.
Maček
6
@macek Ich weiß, dass dies ein paar Monate alt ist, aber seit wann verwenden Arrays nicht numerische Indizes? Niemand sollte eine Eingabe foo [bar] benennen und hoffen, sie als Array zu behandeln. Verwechseln Sie Arrays und Hashes? Ja, [] wird allgemein als Accessor verstanden, aber nicht nur für Arrays. Es ist ein Widerspruch, auch zu sagen, dass es gültiges HTML ist, aber nicht in der HTML-Spezifikation. Ja, der Browser verschluckt sich möglicherweise nicht daran, aber nicht viele Webserver werden wissen, wie man das wie ein Array deserialisiert. Warum? Weil es nicht in der HTML-Spezifikation ist. Daher ist es in der Tat ungültig.
Kroehre
446

Konvertieren Sie Formulare wie ein Chef in JSON


Die aktuelle Quelle ist auf GitHub und Bower .

$ bower installiere jquery-serialize-object


Der folgende Code ist jetzt veraltet .

Der folgende Code kann mit allen Arten von Eingabenamen arbeiten. und behandeln Sie sie so, wie Sie es erwarten würden.

Zum Beispiel:

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

Verwendungszweck

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

Die Zauberei (JavaScript)

(function($){
    $.fn.serializeObject = function(){

        var self = this,
            json = {},
            push_counters = {},
            patterns = {
                "validate": /^[a-zA-Z][a-zA-Z0-9_]*(?:\[(?:\d*|[a-zA-Z0-9_]+)\])*$/,
                "key":      /[a-zA-Z0-9_]+|(?=\[\])/g,
                "push":     /^$/,
                "fixed":    /^\d+$/,
                "named":    /^[a-zA-Z0-9_]+$/
            };


        this.build = function(base, key, value){
            base[key] = value;
            return base;
        };

        this.push_counter = function(key){
            if(push_counters[key] === undefined){
                push_counters[key] = 0;
            }
            return push_counters[key]++;
        };

        $.each($(this).serializeArray(), function(){

            // Skip invalid keys
            if(!patterns.validate.test(this.name)){
                return;
            }

            var k,
                keys = this.name.match(patterns.key),
                merge = this.value,
                reverse_key = this.name;

            while((k = keys.pop()) !== undefined){

                // Adjust reverse_key
                reverse_key = reverse_key.replace(new RegExp("\\[" + k + "\\]$"), '');

                // Push
                if(k.match(patterns.push)){
                    merge = self.build([], self.push_counter(reverse_key), merge);
                }

                // Fixed
                else if(k.match(patterns.fixed)){
                    merge = self.build([], k, merge);
                }

                // Named
                else if(k.match(patterns.named)){
                    merge = self.build({}, k, merge);
                }
            }

            json = $.extend(true, json, merge);
        });

        return json;
    };
})(jQuery);
maček
quelle
17
Das funktioniert also ziemlich gut. Aber es ist falsch benannt: Es gibt kein JSON zurück, wie der Name schon sagt. Stattdessen wird ein Objektliteral zurückgegeben. Außerdem ist es wichtig, nach hasOwnProperty zu suchen, andernfalls haben Ihre Arrays alles, was mit ihrem Prototyp verbunden ist, wie: {numbers: ["1", "3", indexOf: function () {...}]}
frontendbeauty
5
@frontendbeauty toJSON ist genau das, was in der Spezifikation angegeben ist: developer.mozilla.org/en/JSON#toJSON()_method eine unglückliche Fehlbezeichnung.
Ryan Florence
4
@Marek, ich habe hier auf jsfiddle einen Test gemacht . Der Trick besteht darin, Ihre Auswahl richtig zu benennen. <select name="foo" multiple="multiple">funktioniert in keinem Szenario. Wenn Sie jedoch []wie in verwenden <select name="bar[]" multiple="multiple">, wird es gut funktionieren :)
maček
3
Ich wollte darauf hinweisen, dass github.com/serbanghita/formToObject eine ähnliche JavaScript-Methode ist (keine Bibliotheken von Drittanbietern erforderlich), die denselben Job ausführt . Unterstützt "mehrere", ignoriert "deaktivierte" Elemente.
Șerban Ghiță
8
Diese Lösung sollte oben stehen, da sie das Problem verschachtelter Schlüssel als Formularelementnamen behandelt.
SquareCat
283

Was ist falsch mit:

var data = {};
$(".form-selector").serializeArray().map(function(x){data[x.name] = x.value;}); 
mkschreder
quelle
2
@LayZee - Wenn nichts ausgewählt ist, warum möchten Sie es dann auf Ihrem Backend haben? Wenn Sie eine Option auswählen müssen, überprüfen Sie die Eingabe vor der Serialisierung.
Dementic
21
Wenn Sie nichts zurückgeben, warum verwenden Sie nicht einfach .eachstatt .map?
Azerafati
10
Es ist so einfach, weil es super naiv ist ... behandelt keine Kontrollkästchen mit demselben Namen. Jedes Mal, wenn das markierte Element davor überschrieben wird. Sie benötigen auf jeden Fall eine Erkennung des Eingabetyps, um sicherzustellen, dass er ordnungsgemäß serialisiert ist.
Joshua F. Rountree
5
Wenn Sie eine reine jQuery-Lösung wünschen, können Sievar 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;}, {})
Websites
103

Eine feste Version von Tobias Cohens Lösung. Dieser behandelt korrekte Werte wie 0und korrekt ''.

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

Und eine CoffeeScript-Version für Ihre Codierungskomfort:

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
Daniel X Moore
quelle
Im Coffeescript kann dieser erste If-Block umvalue = @value ? ''
nzifnab
Wenn Sie versuchen, Rails-ähnliche Formulare zu serialisieren, möchten Sie möglicherweise das Element root aus den generierten Schlüsseln entfernen. Um dies zu erreichen, habe ich einen neuen Parameter keyMapund die folgende Zeile hinzugefügt : key = if keyMap? then keyMap(@name) else @name. Jetzt können Sie Mapping-Funktion wie übergeben (name) -> name.match(/\[([^\]]+)]/)[1]. Und dann müsste man alle nachfolgenden Änderungen @namezu key, natürlich
Damir Zekić
@ DamirZekić, wenn dein Wurzelelement wäre post, könntest du es einfach tun $('form').serializeObject().post. Keine ausgefallene Zuordnung erforderlich.
Maček
@ DamirZekić Was macht diese Linie? if (!objectData[this.name].push)??
Kittu
@kittu Es wird geprüft, ob objectData[this.name]die Push-Methode vorhanden ist (ungefähr handelt es sich um ein Array). Wenn es sich um ein Array handelt, wird der Wert verschoben. Wenn es sich nicht um ein Array handelt, wird es in ein Array konvertiert, sodass mehrere Werte mit demselben Schlüssel zu einem Array kombiniert werden.
Daniel X Moore
63

Ich benutze Array.prototype.reducees gerne, weil es ein Einzeiler ist und sich nicht auf Underscore.js oder ähnliches stützt :

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

Dies ähnelt der Antwort mit Array.prototype.map, aber Sie müssen Ihren Bereich nicht mit einer zusätzlichen Objektvariablen überladen. One-Stop-Shopping.

WICHTIGER HINWEIS : Formulare mit Eingaben mit doppelten nameAttributen sind gültiges HTML und ein allgemeiner Ansatz. Die Verwendung einer der Antworten in diesem Thread ist in diesem Fall unangemessen (da Objektschlüssel eindeutig sein müssen).

Ethan Brown
quelle
Das ist ziemlich elegant. Es ist jedoch erwähnenswert, dass array.prototype.reduce()dies in IE8 nicht verfügbar ist, da es Teil der ECMAScript 5-Spezifikation ist. Wenn Sie also IE8-Unterstützung benötigen, sollten Sie eine Polyfüllung oder eine andere Lösung verwenden.
Gfullam
3
Stimmt, aber es ist einfach genug, Polyfill zu füllen. Dank der großartigen Arbeit von Microsoft mit dem IE11 Enterprise-Modus sind die IE8-Kopfschmerzen fast vorbei. Ich kümmere mich nicht mehr um einzelne Benutzer mit IE8, aber wenn eine Organisation mit 10.000 Mitarbeitern, die alle IE8 verwenden, hinzukommt, ist das anders. Glücklicherweise arbeitet Microsoft hart an diesem Problem.
Ethan Brown
1
Nun, Ihre IT-Mitarbeiter sollten sich mit dem IE11 Enterprise-Modus befassen - er bietet einen modernen Browser UND eine Möglichkeit, IE8-kompatible Apps auszuführen. Kluger
Ethan Brown
30

Alle diese Antworten schienen mir so übertrieben. Der Einfachheit halber gibt es etwas zu sagen. Solange für alle Formulareingaben das Attribut name festgelegt ist, sollte dies nur mit Jim Dandy funktionieren.

$('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?)
});
Jeffrey Van Alstine
quelle
4
Verarbeitet verschachtelte Formulardaten jedoch nicht, weshalb die Antworten komplizierter werden.
Frontendbeauty
Hat super für mich funktioniert. Nur benötigte Speicherung von Schlüssel-Wert-Paaren; Das Stringifizieren und Speichern in localStorage oder Cookie funktionierte nur gut.
Greg Pettit
23

Es gibt wirklich keine Möglichkeit, dies zu tun, ohne jedes der Elemente zu untersuchen. Was Sie wirklich wissen möchten, ist: "Hat jemand anderes bereits eine Methode geschrieben, die ein Formular in ein JSON-Objekt konvertiert?" So etwas wie das Folgende sollte funktionieren - beachten Sie, dass Sie nur die Formularelemente erhalten, die über einen POST zurückgegeben werden (müssen einen Namen haben). Dies wird nicht getestet .

function formToJSON( selector )
{
     var form = {};
     $(selector).find(':input[name]:enabled').each( function() {
         var self = $(this);
         var name = self.attr('name');
         if (form[name]) {
            form[name] = form[name] + ',' + self.val();
         }
         else {
            form[name] = self.val();
         }
     });

     return form;
}
Tvanfosson
quelle
Es stimmt, ich würde ein Plugin lieben, das dies für mich tun würde. Die Einschränkung, einen Namen zu haben, ist keine große Sache. Werden dadurch alle Felder in einem Formular abgerufen, einschließlich Textbereiche und Auswahlen?
Yisroel
Ich bin mir nicht sicher, ob Sie [deaktiviert] berücksichtigen möchten, aber ich denke nicht, dass dies gesendet / abgeholt werden sollte.
Meder Omuraliev
Es könnte einfacher sein, serializeArray () zu verwenden, um die Karte abzurufen, und dann Code ähnlich dem oben genannten zu verwenden, um sie in ein normales JSON-Objekt zu konvertieren. Auf diese Weise beschäftige ich mich nicht mit dem Formular selbst
Yisroel
2
Die Verwendung des serialisierten Arrays würde funktionieren, aber im Wesentlichen würden Sie die Sammlung zweimal durchlaufen - einmal, um das Array zu erstellen, dann über das Array. Ich sehe keine Notwendigkeit dafür.
Tvanfosson
Ich werde den Selektor für aktiviert / deaktiviert einstellen.
Tvanfosson
23

Wenn Sie Underscore.js verwenden , können Sie Folgendes verwenden:

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

Ich habe überprüft, ob bei allen anderen Antworten ein Problem vorliegt. Wenn der Eingabename ein Array ist, z. B. name[key], sollte er wie folgt generiert werden:

name:{ key : value }


Beispiel: Wenn Sie ein HTML-Formular haben, das dem folgenden ähnlich ist:

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

Es sollte jedoch genau wie der folgende JSON generiert werden und wird nicht zu einem Objekt wie dem folgenden mit allen anderen Antworten. Wenn also jemand so etwas wie den folgenden JSON mitbringen möchte, probieren Sie den folgenden JS-Code aus.

{
    name  : 'value',
    name1 : { key1 : 'value1' },
    name2 : { key2 : 'value2' },
    name3 : { key2 : 'value2' }
}

$.fn.getForm2obj = function() {
  var _ = {};
  $.map(this.serializeArray(), function(n) {
    const keys = n.name.match(/[a-zA-Z0-9_]+|(?=\[\])/g);
    if (keys.length > 1) {
      let tmp = _;
      pop = keys.pop();
      for (let i = 0; i < keys.length, j = keys[i]; i++) {
        tmp[j] = (!tmp[j] ? (pop == '') ? [] : {} : tmp[j]), tmp = tmp[j];
      }
      if (pop == '') tmp = (!Array.isArray(tmp) ? [] : tmp), tmp.push(n.value);
      else tmp[pop] = n.value;
    } else _[keys.pop()] = n.value;
  });
  return _;
}
console.log($('form').getForm2obj());
$('form input').change(function() {
  console.clear();
  console.log($('form').getForm2obj());
});
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<form>
  <input name="name" value="value">
  <input type="checkbox" name="name1[]" value="1" checked="checked">1
  <input type="checkbox" name="name1[]" value="2">2
  <input type="checkbox" name="name1[]" value="3">3<br>
  <input type="radio" name="gender" value="male" checked="checked">male
  <input type="radio" name="gender" value="female"> female
  <input name="name2[key1]" value="value1">
  <input name="one[another][another_one]" value="value4">
  <input name="name3[1][name]" value="value4">
  <input name="name3[2][name]" value="value4">
  <input name="[]" value="value5">
</form>

Bhavik Hirani
quelle
Diese Antwort deckt den erwähnten Fall ab, aber nicht Fälle wie Checkbox [] oder sogar einen [anderen] [another_one]
Leonardo Beal
1
@LeonardoBeal Ich repariere meine Ans .. überprüfen Sie dies jetzt ..!
Bhavik Hirani
Ich bin der Downvoter und ich habe downvoted, weil evales nicht auf diese Weise verwendet werden sollte, weil evales auf diese Weise furchtbar unzuverlässige, fehlerhafte, schlecht funktionierende und möglicherweise unsichere Praktiken fördert.
Jack Giffin
2
Ich kann nicht zustimmen, dass dies eine gute Antwort ist. Und bitte, wenn Sie Antworten schreiben, machen Sie Ihren Code selbsterklärend oder erklären Sie ihn. this.c = function(k,v){ eval("c = typeof "+k+";"); if(c == 'undefined') _t.b(k,v);}ist kurz und nicht erklärend. Ein Entwickler mit weniger Erfahrung kopiert dies einfach, ohne zu verstehen, warum und wie es funktioniert.
iRaS
2
@ JackGiffin Überprüfen Sie jetzt meinen neuen Code, da ich ihn eval()aus meinem Code entfernt habe.
Bhavik Hirani
17

Ok, ich weiß, dass dies bereits eine sehr positive Antwort hat, aber kürzlich wurde eine ähnliche Frage gestellt , und ich wurde auch auf diese Frage verwiesen . Ich möchte meine Lösung auch anbieten, da sie einen Vorteil gegenüber der akzeptierten Lösung bietet: Sie können deaktivierte Formularelemente einfügen (was manchmal wichtig ist, abhängig davon, wie Ihre Benutzeroberfläche funktioniert).

Hier ist meine Antwort von der anderen SO-Frage :

Ursprünglich verwendeten wir die serializeArray()Methode von jQuery , die jedoch keine deaktivierten Formularelemente enthält. Wir deaktivieren häufig Formularelemente, die mit anderen Quellen auf der Seite "synchronisiert" werden, müssen die Daten jedoch weiterhin in unser serialisiertes Objekt aufnehmen. Also serializeArray()ist raus. Wir haben den :inputSelektor verwendet, um alle Eingabeelemente (sowohl aktiviert als auch deaktiviert) in einem bestimmten Container abzurufen und dann $.map()unser Objekt zu erstellen.

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

Beachten Sie, dass jede Ihrer Eingaben ein nameAttribut benötigt, das der Name der Eigenschaft des resultierenden Objekts ist.

Das ist tatsächlich etwas modifiziert von dem, was wir verwendet haben. Wir mussten ein Objekt erstellen, das als .NET IDictionary strukturiert war, also haben wir Folgendes verwendet: (Ich stelle es hier zur Verfügung, falls es nützlich ist)

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

Ich mag diese beiden Lösungen, weil sie eine einfache Verwendung der $.map()Funktion sind und Sie die vollständige Kontrolle über Ihren Selektor haben (also welche Elemente Sie letztendlich in Ihr resultierendes Objekt aufnehmen). Außerdem ist kein zusätzliches Plugin erforderlich. Einfache alte jQuery.

Samuel Meacham
quelle
6
Ich habe dies in einem Projekt versucht. Wenn Sie auf mapdiese Weise ein Array von Objekten mit einer einzigen Eigenschaft erstellen, werden nicht alle Eigenschaften zu einem Objekt zusammengefasst.
Joshperry
16

Diese Funktion sollte mehrdimensionale Arrays zusammen mit mehreren Elementen mit demselben Namen verarbeiten.

Ich benutze es bisher seit ein paar Jahren:

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;
};
Sergey Varlamov
quelle
15

Du kannst das:

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

Siehe JSON .

Harini Sekar
quelle
14

Einzeiler (keine anderen Abhängigkeiten als jQuery) verwendet eine feste Objektbindung für die an die mapMethode übergebene Funktion .

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

Was es macht?

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

Geeignet für progressive Web-Apps (man kann sowohl reguläre Formularübermittlungsaktionen als auch Ajax-Anfragen problemlos unterstützen)

test30
quelle
12

Verwenden:

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

Ausgabe:

{"myfield": "myfield value", "passwordfield": "mypasswordvalue"}
Adrian Seeley
quelle
7

Einfachheit ist hier am besten. Ich habe einen einfachen String-Ersatz durch einen regulären Ausdruck verwendet, und sie haben bisher wie ein Zauber funktioniert. Ich bin kein Experte für reguläre Ausdrücke, aber ich wette, Sie können sogar sehr komplexe Objekte füllen.

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

values.replace(/([^&]+)=([^&]*)/g, function (match, name, value) {
    attributes[name] = value;
});
ngr
quelle
7

Aus einer älteren Antwort:

$('form input, form select').toArray().reduce(function(m,e){m[e.name] = $(e).val(); return m;},{})
Juanpastas
quelle
Soweit ich das beurteilen kann, besteht der Unterschied darin, dass Ihre Lösung nicht davon abhängt, serializeArraysodass Sie die Freiheit haben, die gewünschten Eingaben zu wählen (z. B. können Sie deaktivierte Eingaben einschließen), oder? Dh das ist nicht an irgendein Formular oder das Submit-Ereignis gekoppelt, es ist nur für sich unabhängig?
dvtan
Der einzige kleine Unterschied zur verknüpften Antwort besteht darin, dass keine Daten zum Instanziieren benötigt werden und reducedas Objekt zurückgegeben wird. Dies ist nicht unabhängig, da toArrayes von jQuery stammt.
Websites
6

Ich habe ein Problem mit Tobias Cohens Code gefunden (ich habe nicht genug Punkte, um ihn direkt zu kommentieren), das ansonsten für mich funktioniert. Wenn Sie zwei Auswahloptionen mit demselben Namen haben, beide mit dem Wert = "", erzeugt der ursprüngliche Code "name": "" anstelle von "name": ["", ""]

Ich denke, dies kann behoben werden, indem "|| o [this.name] == ''" zur ersten if-Bedingung hinzugefügt wird:

$.fn.serializeObject = function()
{
    var o = {};
    var a = this.serializeArray();
    $.each(a, function() {
        if (o[this.name] || o[this.name] == '') {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
};
user1134789
quelle
6

Mit der Lösung von maček habe ich sie so geändert, dass sie mit der Art und Weise funktioniert, wie ASP.NET MVC ihre verschachtelten / komplexen Objekte in demselben Formular behandelt. Alles, was Sie tun müssen, ist das Validierungsstück dahingehend zu ändern:

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

Dadurch werden Elemente mit folgenden Namen abgeglichen und dann korrekt zugeordnet:

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

Und

<input type="text" name="zooAnimals[0].name" />
G-Ram
quelle
5

die einfachste und genaueste Methode , die ich für dieses Problem gefunden zu verwenden war bbq - Plugin oder diese ein (was etwa 0,5 K Bytes Größe).

Es funktioniert auch mit mehrdimensionalen Arrays.

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

Roey
quelle
Das scheint gut zu funktionieren. Es gibt ein alternatives Repository für jquery-deparam , das Beschreibungsdateien für bower und npm enthält.
Alf Eaton
4

Für jQuery gibt es ein Plugin, jquery.serializeJSON . Ich habe es jetzt erfolgreich bei einigen Projekten eingesetzt. Es wirkt wie ein Zauber.

Peter Mortensen
quelle
4
const formData = new FormData(form);

let formDataJSON = {};

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

    formDataJSON[key] = value;
}
Steinspitze
quelle
3

Ich bevorzuge diesen Ansatz, weil: Sie nicht über 2 Sammlungen iterieren müssen, bei Bedarf auf andere Dinge als "Name" und "Wert" zugreifen können und Ihre Werte bereinigen können, bevor Sie sie im Objekt speichern ( wenn Sie Standardwerte haben, die Sie beispielsweise nicht speichern möchten).

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

Verwenden Sie wie folgt:

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

Nur in Firefox getestet.

kflorence
quelle
3

Verwandeln Sie alles in ein Objekt (nicht einheitlich getestet)

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

Die Ausgabe des Tests:

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

auf

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

wird ergeben:

{ input: { a: text, b: select }, otherinput: { c: { a: a, 0: b, 1: d }, d: { b: c } }, anotherinput: 1 }
{ input: { b: select } }
eithed
quelle
3

Ich habe ein Problem mit der ausgewählten Lösung gefunden.

Bei Verwendung von Formularen mit Array-basierten Namen stirbt die Funktion jQuery serializeArray () tatsächlich ab.

Ich habe ein PHP-Framework, das Array-basierte Feldnamen verwendet, damit dasselbe Formular in mehreren Ansichten mehrmals auf dieselbe Seite gestellt werden kann. Dies kann nützlich sein, um das Hinzufügen, Bearbeiten und Löschen auf derselben Seite zu platzieren, ohne dass sich die Formularmodelle widersprechen.

Da ich die Formulare seralisieren wollte, ohne diese absolute Basisfunktionalität entfernen zu müssen, habe ich beschlossen, mein eigenes seralizeArray () zu schreiben:

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

Bitte beachten Sie: Dies funktioniert auch außerhalb des Formulars submit (). Wenn also im Rest Ihres Codes ein Fehler auftritt, wird das Formular nicht gesendet, wenn Sie auf eine Link-Schaltfläche mit der Aufschrift "Änderungen speichern" klicken.

Beachten Sie auch, dass diese Funktion niemals zum Validieren des Formulars verwendet werden sollte, nur um die Daten zu sammeln, die zur Validierung an den Server gesendet werden sollen. Die Verwendung eines solchen schwachen und massenzugewiesenen Codes führt zu XSS usw.

Sammaye
quelle
3

Ich hatte in letzter Zeit das gleiche Problem und kam mit diesem .toJSON jQuery-Plugin heraus , das ein Formular in ein JSON-Objekt mit derselben Struktur konvertiert. Dies ist auch besonders nützlich für dynamisch generierte Formulare, bei denen Ihr Benutzer an bestimmten Stellen weitere Felder hinzufügen soll.

Der Punkt ist, dass Sie möglicherweise tatsächlich ein Formular so erstellen möchten, dass es selbst eine Struktur hat. Nehmen wir also an, Sie möchten ein Formular erstellen, in das der Benutzer seine Lieblingsorte in der Stadt einfügt: Sie können sich vorstellen, dass dieses Formular ein <places>...</places>XML-Element darstellt, das a enthält Liste der Orte, die dem Benutzer gefallen, also eine Liste der <place>...</place>Elemente, die jeweils beispielsweise ein <name>...</name>Element, ein <type>...</type>Element und dann eine Liste der <activity>...</activity>Elemente enthalten, um die Aktivitäten darzustellen, die Sie an einem solchen Ort ausführen können. Ihre XML-Struktur würde also folgendermaßen aussehen:

<places>

    <place>

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

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

    </place>

    <place>...</place>

    <place>...</place>

</places>

Wie cool wäre es, ein JSON-Objekt daraus zu haben, das genau diese Struktur darstellt, sodass Sie entweder:

  • Speichern Sie dieses Objekt so, wie es in einer CouchDB- ähnlichen Datenbank ist
  • Lesen Sie es von Ihrer $ _POST [] -Serverseite und rufen Sie ein korrekt verschachteltes Array ab, das Sie dann semantisch bearbeiten können
  • Verwenden Sie ein serverseitiges Skript, um es in eine wohlgeformte XML-Datei zu konvertieren (auch wenn Sie die genaue Struktur a priori nicht kennen).
  • Verwenden Sie es einfach so, wie es in einem Node.js- ähnlichen Serverskript ist

OK, jetzt müssen wir uns überlegen, wie ein Formular eine XML-Datei darstellen kann.

Natürlich ist das <form>Tag das root, aber dann haben wir das <place>Element, das ein Container und kein Datenelement selbst ist, also können wir kein Eingabe-Tag dafür verwenden.

Hier kommt der <fieldset>Tag zum Einsatz! Wir werden <fieldset>Tags verwenden, um alle Containerelemente in unserer Formular- / XML-Darstellung darzustellen und so zu einem Ergebnis wie dem folgenden zu gelangen:

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

Wie Sie in diesem Formular sehen können, verstoßen wir gegen die Regel der eindeutigen Namen. Dies ist jedoch in Ordnung, da sie in ein Array von Elementen konvertiert werden und daher nur durch ihren Index innerhalb des Arrays referenziert werden.

An diesem Punkt können Sie sehen, dass name="array[]"das Formular keinen ähnlichen Namen enthält und alles hübsch, einfach und semantisch ist.

Jetzt möchten wir, dass dieses Formular in ein JSON-Objekt konvertiert wird, das folgendermaßen aussieht:

{'places':{

    'place':[

        {

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

            'activity':[

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

            ]

        },

        {...},

        {...}

    ]

}}

Zu diesem Zweck habe ich hier dieses jQuery-Plugin entwickelt, das von jemandem in diesem Code Review- Thread optimiert wurde und wie folgt aussieht:

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

Ich habe auch diesen einen Blog-Beitrag gemacht , um dies näher zu erläutern.

Dadurch wird alles in einem Formular in JSON konvertiert (sogar Radio und Kontrollkästchen), und Sie müssen nur noch anrufen

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

Ich weiß, dass es viele Möglichkeiten gibt, Formulare in JSON-Objekte zu konvertieren, und dass sie in den meisten Fällen sicher .serialize()und gut .serializeArray()funktionieren. Sie sind hauptsächlich für die Verwendung gedacht, aber ich denke, diese ganze Idee , ein Formular als XML-Struktur mit aussagekräftigen Namen zu schreiben und es in ein zu konvertieren Ein wohlgeformtes JSON-Objekt ist einen Versuch wert. Auch die Tatsache, dass Sie gleichnamige Eingabe-Tags hinzufügen können, ohne sich Sorgen machen zu müssen, ist sehr nützlich, wenn Sie dynamisch generierte Formulardaten abrufen müssen.

Ich hoffe das hilft jemandem!

Onheiron
quelle
Was versuchst du zu machen?
Onheiron
3

Ich habe selbst ein Formular in ein mehrdimensionales JavaScript-Objekt codiert, um es in der Produktion zu verwenden. Das Ergebnis ist https://github.com/serbanghita/formToObject.js .

serbanghita
quelle
Ich habe eine Variation davon für eine sehr spezifische Implementierung verwendet, vielen Dank!
Chris Baker
Vielen Dank, dass Sie mich wissen lassen, dass es nützlich ist. Ich habe einige eingehende Funktionen zu rollen und das motiviert mich.
Șerban Ghiță
3

Eine andere Antwort

document.addEventListener("DOMContentLoaded", function() {
  setInterval(function() {
    var form = document.getElementById('form') || document.querySelector('form[name="userprofile"]');
    var json = Array.from(new FormData(form)).map(function(e,i) {this[e[0]]=e[1]; return this;}.bind({}))[0];
    
    console.log(json)
    document.querySelector('#asJSON').value = JSON.stringify(json);
  }, 1000);
})
<form name="userprofile" id="form">
  <p>Name <input type="text" name="firstname" value="John"/></p>
  <p>Family name <input name="lastname" value="Smith"/></p>
  <p>Work <input name="employment[name]" value="inc, Inc."/></p>
  <p>Works since <input name="employment[since]" value="2017" /></p>
  <p>Photo <input type="file" /></p>
  <p>Send <input type="submit" /></p>
</form>

JSON: <textarea id="asJSON"></textarea>

FormData: https://developer.mozilla.org/en-US/docs/Web/API/FormData

test30
quelle
3

[UPDATE 2020]

Mit einem einfachen Oneliner in Vanille js:

Object.fromEntries(new FormData(form))
aret
quelle
2

Ich mag Samuels Version, aber ich glaube, es hat einen kleinen Fehler. Normalerweise wird JSON als gesendet

{"coreSKU": "PCGUYJS", "name_de": "was auch immer", ...

Nicht so wie

[{"coreSKU": "PCGUYJS"}, {"name_de": "was auch immer"}, ...

Die Funktion IMO sollte also lauten:

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

und um es in ein Datenarray zu packen (wie allgemein erwartet) und es schließlich als adstring App.stringify ({data: App.toJson ('#cropform: input')}) zu senden)

Informationen zur Stringifizierung finden Sie in Frage 3593046 für die Lean-Version und in json2.js für die Version, die alle Eventualitäten abdeckt . Das sollte alles abdecken :)

Frank Nocke
quelle
Vielen Dank. Dies macht (wie Sie erwähnt haben) einen winzigen, aber sehr wichtigen Unterschied.
Adarsha
2

Verwenden Sie für eine schnelle, moderne Lösung das JSONify jQuery-Plugin. Das folgende Beispiel stammt wörtlich aus der GitHub README. Alle Ehre gebührt Kushal Pandya, dem Autor des Plugins.

Gegeben:

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

Laufen:

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

Produziert:

{"name":"Joe User","email":"[email protected]","password":"mypass"}

Wenn Sie mit diesem JSON-Objekt einen jQuery-POST ausführen möchten:

$('#mybutton').click(function() {
    $.post('/api/user', JSON.stringify($('#myform').jsonify()));
}
Jim Stewart
quelle