ChatGPT解决这个技术问题 Extra ChatGPT

Serialize form data to JSON [duplicate]

This question already has answers here: Convert form data to JavaScript object with jQuery (59 answers) Closed 7 years ago.

I want to do some pre-server-validation of a form in a Backbone.js model. To do this I need to get the user input from a form into usable data. I found three methods to do this:

var input = $("#inputId").val(); var input = $("form.login").serialize(); var input = $("form.login").serializeArray();

Unfortunately, none of the provide a good reabable and developable JSON object which I require. I already looked through several questions on Stack Overflow, but I found only some extra libraries.

Doesn't Underscore.js, the current jQuery or Backbone.js provide a helper method?

I can't imagine there is no request for such a function.

HTML

<form class="login">
    <label for="_user_name">username:</label>
    <input type="text" id="_user_name" name="user[name]" value="dev.pus" />
    <label for="_user_pass">password:</label>
    <input type="password" id="_user_pass" name="user[pass]" value="1234" />
    <button type="submit">login</button>
</form>

JavaScript

var formData = $("form.login").serializeObject();
console.log(formData);

Outputs

{
    "name": "dev.pus",
    "pass": "1234"
}

Backbone.js model

var user = new User(formData);
user.save();
jQuery has a plugin for jSON: code.google.com/p/jquery-json, it does not include a helper method.
What's wrong with .serializeArray()?
I need it for forms, I am just wondering that three frameworks don't provide a form mapper...
About duplicate mark This question already has an answer here:: JSON is not JavaScript object, its serialized object!
@xdazz maybe they want { "name": "value" } instead of { "name": "input_name", "value": "input_value" }

c
chim

Here's a function for this use case:

function getFormData($form){
    var unindexed_array = $form.serializeArray();
    var indexed_array = {};

    $.map(unindexed_array, function(n, i){
        indexed_array[n['name']] = n['value'];
    });

    return indexed_array;
}

Usage:

var $form = $("#form_data");
var data = getFormData($form);

The codes overwrites keys with the same name. You should check if indexed_array[n['name']] already exists and if it convert it to array and add the n['value'] there. Of course you also need to check if indexed_array[n['name']] is already an array.
name should be ALWAYS unique (radio buttons, can have only one value!), and if it's not - only last occurrence of field with repeated name is send with request. If you want create multilevel array structure, you have to detect square brackets and from that info build multidimensional arrays. Tip: wrap first part of field name with brackets e.g. somefield[2] => [somefield][2] and use eval to assign value eval('you_array_varialbe'+bracketed_field_name+'=\''+n['value']+'\'')
"name should be ALWAYS unique"... Ummm... checkbox group?
Nice, this should be marked as the correct answer.
@DaniëlCamps is right. A <select multiple> with more than one option selected will fail.
v
vsync

You can do this:

function onSubmit( form ){ var data = JSON.stringify( $(form).serializeArray() ); // <----------- console.log( data ); return false; //don't submit }



see this: http://www.json.org/js.html


Hi, not quite. I am getting something like { "name": "user[name]" value: "dev.pus" } but I want { "name": "dev.pus", "password": "1234" } etc.
@dev.pus: You might need to handle it in the [{"name":"username","value":"foo"}] format. Otherwise, you cannot handle multiple elements with the same name.
if you didnt have multiple elements with same names you could easily translate form data to a JSON string like this: var myjson = {}; $.each(allFormTags, function() { myjson[this.name] = this.value; });
As already mentioned, this gives name=foo value=boo pairs instead of just foo=boo - answer from @Maciej Pyszyński seems more appropriate
This doesn't work well..:3
S
STEEL

The below code should help you out. :)

 //The function is based on http://css-tricks.com/snippets/jquery/serialize-form-to-json/
 <script src="//code.jquery.com/jquery-2.1.0.min.js"></script>

<script>
    $.fn.serializeObject = function() {
        var o = {};
        var a = this.serializeArray();
        $.each(a, function() {
            if (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;
    };

    $(function() {
        $('form.login').on('submit', function(e) {
          e.preventDefault();

          var formData = $(this).serializeObject();
          console.log(formData);
          $('.datahere').html(formData);
        });
    });
</script>

this is great thanks! Anyone have any idea as to whether this will work with uploading files?
@AaronMatthews uploading files uses Blob object. thus wont work
This function is not only 'based on', it is the function from that link. Good thing that CSS tricks gives you permission.
This is great! also working with MVC forms, because the checkboxes are rendered with 2 inputs (one hidden with value false) and with this data serialization, the controller on the other side works out of the box....
Great solution.
P
Peter Mortensen

Use:

var config = {};
jQuery(form).serializeArray().map(function(item) {
    if ( config[item.name] ) {
        if ( typeof(config[item.name]) === "string" ) {
            config[item.name] = [config[item.name]];
        }
        config[item.name].push(item.value);
    } else {
        config[item.name] = item.value;
    }
});

This is not a general solution; a form can have multiple values for the same key. This function will only retain the last value.
indeed, adapted the answer - thanks
the last value is the standard way, and very useful for overwriting previous values.
r
ryanday

I know this doesn't meet the helper function requirement, but the way I've done this is using jQuery's $.each() method

var loginForm = $('.login').serializeArray();
var loginFormObject = {};
$.each(loginForm,
    function(i, v) {
        loginFormObject[v.name] = v.value;
    });

Then I can pass loginFormObject to my backend, or you could create a userobject and save() it in backbone as well.


This is nice and simple, and seems to be perfect for my needs right now. Good work!
I tried to use this for myself as a workaround for other problems, but I found a problem here. On a website done via ASP.NET MVC (Razor style view), the code generates a visible checkbox input and a hidden input. Using your code, loginForm contained both inputs (if the checkbox was checked, false only otherweise) and loginFormObject afterwards got the second input, which was always false. Solution here: in the sub-function of the each, add the following line after the {: if(formObject[v.name] != "true"). This will preserve the true.
P
Peter Mortensen

Trying to solve the same problem (validation without getting into complex plugins and libraries), I created jQuery.serializeJSON, that improves serializeArray to support any kind of nested objects.

This plugin got very popular, but in another project I was using Backbone.js, where I would like to write the validation logic in the Backbone.js models. Then I created Backbone.Formwell, which allows you to show the errors returned by the validation method directly in the form.


amazing, just what I needed!
C
Code Uniquely

I couldn't find an answer that would solve this:

[{name:"Vehicle.Make", value: "Honda"}, {name:"Vehicle.VIN", value: "123"}]

This calls for this object:

{Vehicle: {Make: "Honda", "VIN": "123"}}

So I had to write a serializer of my own that would solve this:

function(formArray){
        var obj = {};
        $.each(formArray, function(i, pair){
            var cObj = obj, pObj, cpName;
            $.each(pair.name.split("."), function(i, pName){
                pObj = cObj;
                cpName = pName;
                cObj = cObj[pName] ? cObj[pName] : (cObj[pName] = {});
            });
            pObj[cpName] = pair.value;
        });
        return obj;
    }

Maybe it will help somebody.


P
Peter Mortensen

If you do not care about repetitive form elements with the same name, then you can do:

var data = $("form.login").serializeArray();
var formData = _.object(_.pluck(data, 'name'), _.pluck(data, 'value'));

I am using Underscore.js here.


P
Peter Mortensen

Here is what I use for this situation as a module (in my formhelper.js):

define(function(){
    FormHelper = {};

    FormHelper.parseForm = function($form){
        var serialized = $form.serializeArray();
        var s = '';
        var data = {};
        for(s in serialized){
            data[serialized[s]['name']] = serialized[s]['value']
        }
        return JSON.stringify(data);
    }

    return FormHelper;
});

It kind of sucks that I can't seem to find another way to do what I want to do.

This does return this JSON for me:

{"first_name":"John","last_name":"Smith","age":"30"}

are you sure that if a form have multiple values for the same key. This function will only retain the last value?
P
Peter Mortensen

If you are sending the form with JSON you must remove [] in the sending string. You can do that with the jQuery function 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;
}

P
Peter Mortensen

Using Underscore.js:

function serializeForm($form){
    return _.object(_.map($form.serializeArray(), function(item){return [item.name, item.value]; }));
}

This is not a general solution; a form can have multiple values for the same key. This function will only retain the last value.
r
rbarriuso

Using jQuery and avoiding serializeArray, the following code serializes and sends the form data in JSON format:

$("#commentsForm").submit(function(event){
    var formJqObj = $("#commentsForm");
    var formDataObj = {};
    (function(){
        formJqObj.find(":input").not("[type='submit']").not("[type='reset']").each(function(){
            var thisInput = $(this);
            formDataObj[thisInput.attr("name")] = thisInput.val();
        });
    })();
    $.ajax({
        type: "POST",
        url: YOUR_URL_HERE,
        data: JSON.stringify(formDataObj),
        contentType: "application/json"
    })
    .done(function(data, textStatus, jqXHR){
        console.log("Ajax completed: " + data);
    })
    .fail(function(jqXHR, textStatus, errorThrown){
        console.log("Ajax problem: " + textStatus + ". " + errorThrown);
    });
    event.preventDefault();
});

C
Community

Well, here's a handy plugin for it: https://github.com/macek/jquery-serialize-object

The issue for it is:

Moving ahead, on top of core serialization, .serializeObject will support correct serializaton for boolean and number values, resulting valid types for both cases. Look forward to these in >= 2.1.0


P
Peter Mortensen

My contribution:

function serializeToJson(serializer){
    var _string = '{';
    for(var ix in serializer)
    {
        var row = serializer[ix];
        _string += '"' + row.name + '":"' + row.value + '",';
    }
    var end =_string.length - 1;
    _string = _string.substr(0, end);
    _string += '}';
    console.log('_string: ', _string);
    return JSON.parse(_string);
}

var params = $('#frmPreguntas input').serializeArray();
params = serializeToJson(params);

I don't think it's a good idea to build the JSON string manually when there are built-in functions that do that for you. This is rife with potential errors.
d
dev.pus

Found one possible helper:

https://github.com/theironcook/Backbone.ModelBinder

and for people who don't want to get in contact with forms at all: https://github.com/powmedia/backbone-forms

I will take a closer look at the first link and than give some feedback :)


See stackoverflow.com/questions/1184624/…: var data = {}; $(".form-selector").serializeArray().map(function(x){data[x.name] = x.value;});
Here it is the one-liner: $("form.login").serializeArray().reduce( (f,c) => { f[c.name]=c.value; return f;}, {} );

关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now