Chuyển đổi dữ liệu biểu mẫu thành đối tượng JavaScript bằng jQuery


1624

Làm cách nào để chuyển đổi tất cả các thành phần của biểu mẫu của tôi thành đối tượng JavaScript?

Tôi muốn có một số cách tự động xây dựng một đối tượng JavaScript từ biểu mẫu của mình mà không phải lặp qua từng phần tử. Tôi không muốn một chuỗi, như được trả về bởi $('#formid').serialize();, tôi cũng không muốn bản đồ được trả về bởi$('#formid').serializeArray();


16
bởi vì chuỗi đầu tiên trả về một chuỗi, chính xác như những gì bạn nhận được nếu bạn gửi biểu mẫu bằng phương thức GET và chuỗi thứ hai cung cấp cho bạn một mảng các đối tượng, mỗi chuỗi có một cặp giá trị tên. Tôi muốn rằng nếu tôi có một trường có tên là "email", tôi sẽ nhận được một đối tượng cho phép tôi truy xuất giá trị đó bằng obj.email. Với serializeArray (), tôi sẽ phải làm một cái gì đó như obj [indexOfEuity] .value
Yisroel

2
@James - Câu trả lời được chấp nhận khi sử dụng thư viện JSON-js của D. Crockford. Dưới đây là một ví dụ: github.com/ussyese22/google-app-engine-jappstart/blob/master/src/ mẹo
Taylor Leese

4
@Taylor Có, tôi muốn nói câu trả lời đúng sử dụng hàm lib và Tobias của Crockford như vậy: JSON.opesify ($ ('myForm'). SerializeObject ())
James McCormack

5
@Jonz - Có những lý do khác ngoài việc gửi / truyền để sử dụng phần tử biểu mẫu. Nếu bạn đang thực hiện bất kỳ thao tác nặng nào với các giá trị biểu mẫu trong JavaScript (ví dụ: ứng dụng một trang), sẽ rất tiện lợi khi đặt chúng ở định dạng đối tượng để truy cập & thao tác. Ngoài ra, HTTP Post và Get chuỗi truy vấn không phải là định dạng duy nhất để di chuyển dữ liệu xung quanh.
Patrick M

3
Một js tốt tôi đã đi qua >> github.com/marioizquierdo/jquery.serializeJSON
Bongs

Câu trả lời:


1657

serializeArrayđã làm chính xác điều đó. Bạn chỉ cần xoa bóp dữ liệu vào định dạng yêu cầu của bạn:

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

Cảnh giác với các trường ẩn có cùng tên với đầu vào thực vì chúng sẽ bị ghi đè.


4
như tvanfosson nói, tại sao lặp đi lặp lại bộ sưu tập hai lần?
Yisroel

69
Bạn có nghĩa là "tại sao sử dụng serializeArray để lấy dữ liệu ở vị trí đầu tiên?" Vì serializeArray đã được viết, nên đơn vị được thử nghiệm trên nhiều trình duyệt và về mặt lý thuyết có thể được cải thiện trong các phiên bản sau của jQuery. Càng ít mã bạn viết mà phải truy cập trực tiếp vào những thứ không nhất quán như các phần tử DOM, mã của bạn sẽ càng ổn định.
Tobias Cohen

56
Được cảnh báo, serializeArray () sẽ không bao gồm các yếu tố bị vô hiệu hóa. Tôi thường vô hiệu hóa các yếu tố đầu vào được đồng bộ hóa với các yếu tố khác trên trang, nhưng tôi vẫn muốn chúng được bao gồm trong đối tượng được tuần tự hóa của mình. Bạn nên sử dụng một cái gì đó như $.map( $("#container :input"), function(n, i) { /* n.name and $(n).val() */ } );nếu bạn cần bao gồm các yếu tố bị vô hiệu hóa.
Samuel Meacham

22
@TobiasCohen Nó không xử lý các foo[bar]kiểu đầu vào như mong đợi, chưa kể hầu hết các loại tên đầu vào khác. Sau khi rất thất vọng với các giải pháp nông cạn cho vấn đề này, cuối cùng tôi đã viết plugin jQuery của riêng mình - chi tiết trong câu trả lời tôi cung cấp cho câu hỏi này.
maček

6
@macek Tôi biết đây là một vài tháng tuổi, nhưng từ khi nào các mảng sử dụng các chỉ mục không phải là số? Không ai nên đặt tên cho một foo [bar] đầu vào và hy vọng coi nó như một mảng. Bạn có nhầm lẫn mảng và băm? Có, [] thường được hiểu là một người truy cập nhưng không chỉ cho mảng. Cũng nói rằng HTML hợp lệ nhưng không có trong đặc tả HTML là một mâu thuẫn. Vâng, trình duyệt có thể không bị nghẹt thở, nhưng không có nhiều trình duyệt web sẽ biết cách khử lưu lượng giống như một mảng. Tại sao? Bởi vì nó không có trong đặc tả HTML. Do đó, nó thực sự không hợp lệ.
kroehre

446

Chuyển đổi biểu mẫu thành JSON như một ông chủ


Nguồn hiện tại là trên GitHubBower .

$ bower cài đặt jquery-serialize-object


Các mã sau đây là bây giờ không được dùng nữa .

Đoạn mã sau có thể hoạt động với tất cả các loại tên đầu vào; và xử lý chúng như bạn mong đợi.

Ví dụ:

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

Sử dụng

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

Phù thủy (JavaScript)

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

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


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

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

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

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

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

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

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

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

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

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

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

        return json;
    };
})(jQuery);

17
Vì vậy, nó hoạt động khá tốt. Nhưng nó được đặt tên sai: nó không trả về JSON, như tên của nó. Thay vào đó, nó trả về một đối tượng theo nghĩa đen. Ngoài ra, điều quan trọng là kiểm tra hasOwnProperty, nếu không, mảng của bạn có bất cứ thứ gì được gắn vào nguyên mẫu của chúng, như: {Numbers: ["1", "3", indexOf: function () {...}]}
frontendbeauty

5
@frontendbeauty thực sự, toJSON chính xác là những gì thông số kỹ thuật nói rằng nó nên được gọi là: developer.mozilla.org/en/JSON#toJSON()_method một cách hiểu sai đáng tiếc.
Ryan Florence

4
@Marek, tôi đã làm một bài kiểm tra ở đây trên jsfiddle . Bí quyết là đặt tên cho lựa chọn của bạn đúng. <select name="foo" multiple="multiple">sẽ không hoạt động trong bất kỳ kịch bản. Tuy nhiên, nếu bạn sử dụng [], như trong <select name="bar[]" multiple="multiple">, nó sẽ hoạt động tốt :)
maček

3
Muốn chỉ ra rằng github.com/serbanghita/formToObject là một phương thức JavaScript tương tự (không cần thư viện của bên thứ 3) thực hiện cùng một công việc. Hỗ trợ 'nhiều', bỏ qua các yếu tố 'bị vô hiệu hóa'.
Șerban Ghiță

8
Giải pháp này nên được đặt lên hàng đầu vì nó giải quyết vấn đề về các khóa lồng nhau như tên thành phần của biểu mẫu.
SquareCat

283

Có chuyện gì với:

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

2
@LayZee - nếu không có gì được chọn, tại sao bạn lại muốn nó ở mặt sau của bạn? nếu bạn phải chọn một tùy chọn, xác nhận đầu vào trước khi tuần tự hóa.
Mất trí nhớ

21
nếu bạn không trả lại bất cứ thứ gì, tại sao bạn không sử dụng .eachthay vì .map??
azerafati

10
Điều đó thật đơn giản bởi vì nó siêu ngây thơ ... không xử lý các hộp kiểm có cùng tên. Mỗi lần nó sẽ ghi đè lên mục đã kiểm tra trước nó. Bạn chắc chắn sẽ cần một số phát hiện loại đầu vào để đảm bảo nó được tuần tự hóa đúng.
Joshua F. Rountree

5
Nếu bạn muốn một giải pháp jQuery thuần túy, bạn có thể sử dụngvar 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;}, {})
trang web

103

Một phiên bản cố định của giải pháp Tobias Cohen. Điều này xử lý chính xác các giá trị giả như 0''.

jQuery.fn.serializeObject = function() {
  var arrayData, objectData;
  arrayData = this.serializeArray();
  objectData = {};

  $.each(arrayData, function() {
    var value;

    if (this.value != null) {
      value = this.value;
    } else {
      value = '';
    }

    if (objectData[this.name] != null) {
      if (!objectData[this.name].push) {
        objectData[this.name] = [objectData[this.name]];
      }

      objectData[this.name].push(value);
    } else {
      objectData[this.name] = value;
    }
  });

  return objectData;
};

Và một phiên bản CoffeeScript để thuận tiện cho việc mã hóa của bạn:

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

Trong coffeescript, khối đầu tiên đó có thể rút ngắn thànhvalue = @value ? ''
nzifnab

Và nếu bạn đang cố gắng tuần tự hóa các biểu mẫu giống như Rails, bạn có thể muốn xóa gốc phần tử khỏi các khóa được tạo. Để đạt được điều đó, tôi đã thêm một thông số mới keyMapvà dòng sau : key = if keyMap? then keyMap(@name) else @name. Bây giờ bạn có thể vượt qua chức năng ánh xạ như thế nào (name) -> name.match(/\[([^\]]+)]/)[1]. Và rồi người ta sẽ cần phải thay đổi tất cả sau đó @nameđến key, tất nhiên
Damir Zekić

@ DamirZekić, nếu yếu tố gốc của bạn là post, bạn chỉ cần làm $('form').serializeObject().post. Không cần lập bản đồ ưa thích.
maček

@ DamirZekić Dòng này đang làm gì? if (!objectData[this.name].push)??
kittu

@kittu Đó là kiểm tra nếu objectData[this.name]có phương thức đẩy (đại khái, nó có phải là một mảng không). Nếu nó là một mảng, nó sẽ đẩy giá trị, nếu nó không phải là một mảng, nó sẽ chuyển đổi nó thành một mảng để nhiều giá trị có cùng khóa sẽ được kết hợp thành một mảng.
Daniel X Moore

63

Tôi thích sử dụng Array.prototype.reducevì nó là một lớp lót và nó không dựa vào Underscore.js hoặc tương tự:

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

Điều này tương tự với câu trả lời bằng cách sử dụng Array.prototype.map, nhưng bạn không cần phải làm lộn xộn phạm vi của mình với một biến đối tượng bổ sung. Điểm dừng mua sắm.

LƯU Ý QUAN TRỌNG : Các biểu mẫu có đầu vào có namethuộc tính trùng lặp là HTML hợp lệ và thực sự là một cách tiếp cận phổ biến. Sử dụng bất kỳ câu trả lời nào trong luồng này sẽ không phù hợp trong trường hợp đó (vì các khóa đối tượng phải là duy nhất).


Điều này là khá thanh lịch. Nhưng điều đáng chú ý array.prototype.reduce()là không có sẵn trong IE8 vì đây là một phần của đặc tả ECMAScript 5. Vì vậy, nếu bạn cần hỗ trợ IE8, bạn sẽ muốn sử dụng một polyfill hoặc một giải pháp khác hoàn toàn.
gfullam

3
Đúng, nhưng nó đủ dễ để polyfill. Ngoài ra, vấn đề đau đầu về IE8 đã gần hết , nhờ vào công việc tuyệt vời của Microsoft với IE11 Enterprise Mode - Tôi không còn phục vụ cho người dùng cá nhân với IE8, nhưng khi một tổ chức có 10.000 nhân viên sử dụng IE8 ... thì khác. May mắn thay, Microsoft đang làm việc chăm chỉ về vấn đề đó.
Ethan Brown

1
Chà, bạn nên để những người làm CNTT của bạn nhìn vào chế độ IE11 Enterprise - nó cung cấp một trình duyệt hiện đại VÀ một cách để chạy các ứng dụng tương thích với IE8. Di chuyển thông minh trên phần của Microsoft: howtogeek.com/184634/ Mạnh
Ethan Brown

30

Tất cả những câu trả lời này dường như quá cao đối với tôi. Có một cái gì đó để nói cho đơn giản. Miễn là tất cả các đầu vào biểu mẫu của bạn có thuộc tính tên được đặt, nó sẽ hoạt động chỉ là 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?)
});

4
Không xử lý dữ liệu biểu mẫu lồng nhau, đó là lý do tại sao các câu trả lời trở nên phức tạp hơn.
frontendbeauty

Làm việc tuyệt vời cho tôi. Chỉ cần lưu trữ các cặp khóa-giá trị; xâu chuỗi và sau đó lưu vào localStorage hoặc cookie chỉ hoạt động tốt.
Greg Pettit

23

Thực sự không có cách nào để làm điều này mà không kiểm tra từng yếu tố. Điều bạn thực sự muốn biết là "có ai khác đã viết một phương thức chuyển đổi một biểu mẫu thành một đối tượng JSON không?" Một cái gì đó giống như sau sẽ hoạt động - lưu ý rằng nó sẽ chỉ cung cấp cho bạn các thành phần biểu mẫu sẽ được trả về qua POST (phải có tên). Điều này không được thử nghiệm .

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

đúng, tôi thích một plugin sẽ làm điều này cho tôi. giới hạn của việc có một tên là không có vấn đề lớn. điều này sẽ kéo tất cả các trường trong một hình thức, bao gồm cả textareas và chọn?
Yisroel

không chắc chắn nếu bạn muốn tài khoản cho [bị vô hiệu hóa] nhưng tôi không nghĩ rằng nên gửi / nhặt.
trung gian ometiciev

có thể đơn giản hơn khi sử dụng serializeArray () để lấy bản đồ và sau đó sử dụng mã tương tự như trên để chuyển đổi nó thành một đối tượng JSON bình thường, theo cách này tôi không xử lý biểu mẫu
Yisroel

2
Sử dụng serializedArray sẽ hoạt động, nhưng về cơ bản, bạn sẽ lặp lại bộ sưu tập hai lần - một lần để tạo ra mảng, sau đó qua mảng. Tôi không thấy sự cần thiết cho điều đó.
tvanfosson

Tôi sẽ điều chỉnh bộ chọn để bật / tắt.
tvanfosson

23

Nếu bạn đang sử dụng Underscore.js, bạn có thể sử dụng tương đối súc tích:

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

19

Tôi đã kiểm tra rằng có một vấn đề với tất cả các câu trả lời khác, rằng nếu tên đầu vào là một mảng, chẳng hạn như name[key], thì nó sẽ được tạo như thế này:

name:{ key : value }


Ví dụ: Nếu bạn có một biểu mẫu HTML tương tự như biểu mẫu bên dưới:

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

Nhưng nó nên được tạo giống như JSON bên dưới và không trở thành một đối tượng như sau với tất cả các câu trả lời khác. Vì vậy, nếu bất cứ ai muốn mang một cái gì đó giống như JSON sau đây, hãy thử mã JS bên dưới.

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


Câu trả lời này không bao gồm trường hợp được đề cập, nhưng nó không bao gồm các trường hợp như hộp kiểm [] hoặc thậm chí một [khác] [other_one]
Leonardo Beal

1
@LeonardoBeal tôi sửa ans của tôi .. kiểm tra cái này ngay bây giờ ..!
Bhasta Hirani

Tôi là người downvoter và tôi bị hạ cấp vì evalkhông nên sử dụng theo cách này bởi vì eval, khi được sử dụng theo cách này, sẽ thúc đẩy các thực tiễn không đáng tin cậy, lỗi, không phù hợp và có khả năng không an toàn.
Jack Giffin

2
Tôi không thể đồng ý đây là một câu trả lời tốt. Và xin vui lòng khi bạn viết câu trả lời làm cho mã của bạn tự giải thích hoặc giải thích nó. this.c = function(k,v){ eval("c = typeof "+k+";"); if(c == 'undefined') _t.b(k,v);}là ngắn và không giải thích. Một nhà phát triển có ít kinh nghiệm sẽ chỉ sao chép điều này mà không hiểu tại sao và làm thế nào nó hoạt động.
iRaS

2
@JackGiffin Kiểm tra mã mới của tôi ngay bây giờ vì tôi đã xóa eval()khỏi mã của mình.
Bhasta Hirani

17

Ok, tôi biết điều này đã có một câu trả lời được đánh giá cao, nhưng một câu hỏi tương tự khác đã được hỏi gần đây, và tôi cũng được chuyển đến câu hỏi này. Tôi cũng muốn cung cấp giải pháp của mình, vì nó mang lại lợi thế cho giải pháp được chấp nhận: Bạn có thể bao gồm các yếu tố biểu mẫu bị vô hiệu hóa (đôi khi rất quan trọng, tùy thuộc vào cách các chức năng UI của bạn)

Đây là câu trả lời của tôi từ câu hỏi SO khác :

Ban đầu, chúng tôi đã sử dụng serializeArray()phương thức của jQuery , nhưng điều đó không bao gồm các thành phần biểu mẫu bị vô hiệu hóa. Chúng tôi thường sẽ vô hiệu hóa các thành phần biểu mẫu "đồng bộ hóa" với các nguồn khác trên trang, nhưng chúng tôi vẫn cần đưa dữ liệu vào đối tượng được tuần tự hóa. Thế serializeArray()là hết. Chúng tôi đã sử dụng :inputbộ chọn để nhận tất cả các yếu tố đầu vào (cả được bật và tắt) trong một thùng chứa nhất định và sau đó $.map()để tạo đối tượng của chúng tôi.

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

Lưu ý rằng để làm việc này, mỗi đầu vào của bạn sẽ cần một namethuộc tính, đó sẽ là tên của thuộc tính của đối tượng kết quả.

Đó thực sự là một chút sửa đổi từ những gì chúng ta sử dụng. Chúng tôi cần tạo một đối tượng có cấu trúc như .NET IDadata, vì vậy chúng tôi đã sử dụng điều này: (Tôi cung cấp nó ở đây trong trường hợp nó hữu ích)

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

Tôi thích cả hai giải pháp này, vì chúng là những cách sử dụng đơn giản của $.map()hàm và bạn có toàn quyền kiểm soát bộ chọn của mình (vì vậy, phần tử nào bạn kết thúc bao gồm trong đối tượng kết quả của bạn). Ngoài ra, không cần thêm plugin. JQuery cũ đơn giản.


6
Tôi đã thử điều này trong một dự án, sử dụng mapnhư thế này sẽ tạo ra một mảng các đối tượng với một thuộc tính duy nhất, nó không thu gọn tất cả các thuộc tính thành một đối tượng.
joshperry

16

Hàm này sẽ xử lý các mảng nhiều chiều cùng với nhiều phần tử có cùng tên.

Tôi đã sử dụng nó được một vài năm cho đến nay:

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

15

Bạn có thể làm được việc này:

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

Xem JSON .


14

One-liner (không phụ thuộc ngoài jQuery), sử dụng liên kết đối tượng cố định cho hàm được truyền cho mapphương thức.

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

Những gì nó làm?

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

phù hợp với các ứng dụng web lũy tiến (người ta có thể dễ dàng hỗ trợ cả hành động gửi biểu mẫu thông thường cũng như yêu cầu ajax)


12

Sử dụng:

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

Đầu ra:

{"myfield": "myfield value", "passwordfield": "mypasswordvalue"}

7

Đơn giản là tốt nhất ở đây. Tôi đã sử dụng một chuỗi đơn giản thay thế bằng một biểu thức thông thường và cho đến nay chúng hoạt động như một bùa mê. Tôi không phải là một chuyên gia biểu hiện thông thường, nhưng tôi cá rằng bạn thậm chí có thể cư trú các đối tượng rất phức tạp.

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

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

7

Từ một số câu trả lời cũ hơn :

$('form input, form select').toArray().reduce(function(m,e){m[e.name] = $(e).val(); return m;},{})

Từ những gì tôi có thể nói, sự khác biệt là giải pháp của bạn không phụ thuộc vào serializeArraynên bạn có quyền tự do lựa chọn bất kỳ đầu vào nào bạn muốn (ví dụ: bạn có thể bao gồm các đầu vào bị vô hiệu hóa), phải không? Tức là điều này không được kết hợp với bất kỳ hình thức hoặc sự kiện gửi, nó chỉ độc lập với chính nó?
dvtan

sự khác biệt nhỏ duy nhất với câu trả lời được liên kết là không có dữ liệu cần thiết để khởi tạo, reducetrả về đối tượng. Điều này không độc lập vì toArraylà từ jQuery.
trang web

6

Tôi đã tìm thấy một vấn đề với mã của Tobias Cohen (tôi không có đủ điểm để nhận xét trực tiếp về nó), điều này có tác dụng với tôi. Nếu bạn có hai tùy chọn chọn có cùng tên, cả hai đều có giá trị = "", mã gốc sẽ tạo ra "name": "" thay vì "name": ["", ""]

Tôi nghĩ điều này có thể khắc phục bằng cách thêm "|| o [this.name] == ''" vào điều kiện đầu tiên:

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

6

Sử dụng giải pháp của maček , tôi đã sửa đổi nó để hoạt động với cách ASP.NET MVC xử lý các đối tượng phức tạp / lồng nhau của chúng trên cùng một biểu mẫu. Tất cả bạn phải làm là sửa đổi phần xác nhận thành này:

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

Điều này sẽ khớp và sau đó ánh xạ chính xác các yếu tố với các tên như:

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

<input type="text" name="zooAnimals[0].name" />

5

cách đơn giản nhất và chính xác nhất tôi tìm thấy cho vấn đề này là sử dụng bbq Plugin hay này một (đó là khoảng 0.5K byte kích thước).

nó cũng hoạt động với các mảng đa chiều.

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


Điều này dường như làm việc độc đáo. Có một kho lưu trữ thay thế cho jquery-deparam bao gồm các tệp mô tả cho bower và npm.
Alf Eaton

4

Có một plugin để làm điều đó cho jQuery, jquery.serializeJSON . Tôi đã sử dụng nó thành công trên một vài dự án bây giờ. Nó hoạt động như một say mê.


4
const formData = new FormData(form);

let formDataJSON = {};

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

    formDataJSON[key] = value;
}

3

Tôi thích cách tiếp cận này bởi vì: bạn không phải lặp lại hơn 2 bộ sưu tập, bạn có thể nhận được những thứ khác ngoài "tên" và "giá trị" nếu bạn cần và bạn có thể vệ sinh các giá trị của mình trước khi lưu trữ chúng trong đối tượng ( nếu bạn có các giá trị mặc định mà bạn không muốn lưu trữ chẳng hạn).

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

Sử dụng như vậy:

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

Chỉ được thử nghiệm trong Firefox.


3

Biến bất cứ thứ gì thành một đối tượng (không phải đơn vị thử nghiệm)

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

Đầu ra của bài kiểm tra:

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

trên

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

sẽ mang lại:

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

3

Tôi tìm thấy một vấn đề với các giải pháp được lựa chọn.

Khi sử dụng các biểu mẫu có tên dựa trên mảng, hàm jQuery serializeArray () thực sự chết.

Tôi có một khung công tác PHP sử dụng các tên trường dựa trên mảng để cho phép cùng một biểu mẫu được đặt trên cùng một trang nhiều lần trong nhiều chế độ xem. Điều này có thể thuận tiện để đặt cả thêm, chỉnh sửa và xóa trên cùng một trang mà không có mô hình biểu mẫu xung đột.

Vì tôi muốn sắp xếp các biểu mẫu mà không cần phải loại bỏ chức năng cơ bản tuyệt đối này, tôi quyết định viết seralizeArray của riêng tôi ():

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

Xin lưu ý: Điều này cũng hoạt động bên ngoài biểu mẫu gửi () vì vậy nếu xảy ra lỗi trong phần còn lại của mã, biểu mẫu sẽ không gửi nếu bạn đặt trên nút liên kết có nội dung "lưu thay đổi".

Cũng lưu ý rằng chức năng này không bao giờ được sử dụng để xác thực mẫu chỉ để thu thập dữ liệu gửi đến phía máy chủ để xác thực. Sử dụng mã yếu và được gán khối lượng lớn như vậy SILL gây ra XSS , v.v.


3

Tôi đã có cùng một vấn đề gần đây và đi ra với plugin .toJSON jQuery này để chuyển đổi một biểu mẫu thành một đối tượng JSON có cùng cấu trúc. Điều này cũng đặc biệt hữu ích cho các biểu mẫu được tạo động mà bạn muốn cho phép người dùng của mình thêm nhiều trường ở những nơi cụ thể.

Vấn đề là bạn thực sự có thể muốn xây dựng một biểu mẫu để nó có cấu trúc, vì vậy giả sử bạn muốn tạo một biểu mẫu nơi người dùng chèn các địa điểm yêu thích của mình trong thị trấn: bạn có thể tưởng tượng biểu mẫu này để biểu thị một <places>...</places>phần tử XML có chứa một danh sách các địa điểm mà người dùng thích, do đó, một danh sách các <place>...</place>yếu tố mà mỗi nơi chứa, ví dụ như một <name>...</name>yếu tố, một <type>...</type>yếu tố và sau đó là danh sách<activity>...</activity> yếu tố để thể hiện các hoạt động bạn có thể thực hiện ở một nơi như vậy. Vì vậy, cấu trúc XML của bạn sẽ như thế này:

<places>

    <place>

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

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

    </place>

    <place>...</place>

    <place>...</place>

</places>

Thật tuyệt vời khi có một đối tượng JSON trong số này sẽ đại diện cho cấu trúc chính xác này để bạn có thể:

  • Lưu trữ đối tượng này như trong bất kỳ cơ sở dữ liệu nào giống CouchDB
  • Đọc nó từ phía máy chủ $ _POST [] của bạn và truy xuất một mảng được lồng chính xác, sau đó bạn có thể thao tác về mặt ngữ nghĩa
  • Sử dụng một số tập lệnh phía máy chủ để chuyển đổi nó thành tệp XML được định dạng tốt (ngay cả khi bạn không biết cấu trúc chính xác của nó a-prori)
  • Chỉ bằng cách nào đó sử dụng nó như trong bất kỳ tập lệnh máy chủ nào giống Node.js

OK, vì vậy bây giờ chúng ta cần nghĩ làm thế nào một biểu mẫu có thể biểu thị một tệp XML.

Tất nhiên <form>thẻ là root, nhưng sau đó chúng ta có<place> phần tử đó là vùng chứa chứ không phải phần tử dữ liệu, vì vậy chúng ta không thể sử dụng thẻ đầu vào cho nó.

Đây là nơi <fieldset>thẻ có ích! Chúng tôi sẽ sử dụng <fieldset>các thẻ để thể hiện tất cả các thành phần chứa trong biểu diễn biểu mẫu / XML của chúng tôi và để có được kết quả như thế này:

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

Như bạn có thể thấy trong biểu mẫu này, chúng tôi đang phá vỡ quy tắc của các tên duy nhất, nhưng điều này không sao vì chúng sẽ được chuyển đổi thành một mảng phần tử do đó chúng sẽ chỉ được tham chiếu bởi chỉ mục của chúng trong mảng.

Tại thời điểm này, bạn có thể thấy làm thế nào không có name="array[]"tên giống như trong biểu mẫu và mọi thứ đều đẹp, đơn giản và ngữ nghĩa.

Bây giờ chúng tôi muốn biểu mẫu này được chuyển đổi thành một đối tượng JSON trông giống như thế này:

{'places':{

    'place':[

        {

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

            'activity':[

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

            ]

        },

        {...},

        {...}

    ]

}}

Để làm điều này, tôi đã phát triển plugin jQuery này ở đây mà ai đó đã giúp tối ưu hóa trong chuỗi Đánh giá mã này và trông như thế này:

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

Tôi cũng đã thực hiện một bài đăng blog này để giải thích điều này nhiều hơn.

Điều này chuyển đổi mọi thứ trong một biểu mẫu thành JSON (thậm chí cả hộp radio và hộp kiểm) và tất cả những gì bạn còn lại phải làm là gọi

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

Tôi biết có nhiều cách để chuyển đổi các biểu mẫu thành các đối tượng JSON và chắc chắn .serialize().serializeArray()hoạt động tốt trong hầu hết các trường hợp và chủ yếu được sử dụng, nhưng tôi nghĩ rằng toàn bộ ý tưởng viết một biểu mẫu dưới dạng cấu trúc XML với các tên có ý nghĩa và chuyển đổi nó thành một Đối tượng JSON được định dạng tốt rất đáng để thử, thực tế là bạn có thể thêm các thẻ đầu vào cùng tên mà không phải lo lắng là rất hữu ích nếu bạn cần truy xuất lại dữ liệu biểu mẫu được tạo động.

Tôi hi vọng điêu nay se giup được ai đo!


bạn đang cố làm gì vậy?
Onheiron

3

Bản thân tôi đã mã hóa một biểu mẫu cho một đối tượng JavaScript đa chiều để sử dụng nó trong sản xuất. Kết quả là https://github.com/serbanghita/formToObject.js .


Tôi đã sử dụng một biến thể của điều này để thực hiện rất cụ thể, cảm ơn rất nhiều!
Chris Baker

Cảm ơn đã cho tôi biết rằng nó hữu ích. Tôi có một số tính năng đến để cuộn và điều này thúc đẩy tôi.
Șerban Ghiță

3

Một câu trả lời khác

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

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

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


3

[CẬP NHẬT 2020]

Với một oneliner đơn giản trong vanilla js:

Object.fromEntries(new FormData(form))

2

Tôi thích phiên bản samuels, nhưng tôi tin rằng nó có một lỗi nhỏ. Thông thường JSON được gửi dưới dạng

{"coreSKU": "PCGUYJS", "name_de": "sao cũng được", ...

KHÔNG như

[{"coreSKU": "PCGUYJS"}, {"name_de": "sao cũng được"}, ...

Vì vậy, hàm IMO nên đọc:

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

và để bọc nó trong mảng dữ liệu (như thường được mong đợi), và cuối cùng gửi nó dưới dạng App.opesify ({data: App.toJson ('#cropform: input')})

Để xem chuỗi, hãy xem Câu hỏi 3593046 cho phiên bản nạc, tại json2.js cho phiên bản được bảo hiểm theo mọi sự kiện. Điều đó sẽ bao gồm tất cả :)


Cảm ơn bạn .. điều này làm cho (như bạn đã đề cập) sự khác biệt nhỏ nhưng rất quan trọng.
Adarsha

2

Để có giải pháp nhanh chóng, hiện đại, hãy sử dụng plugin JSONify jQuery. Ví dụ dưới đây được lấy nguyên văn từ GitHub README. Tất cả tín dụng cho Kushal Pandya, tác giả của plugin.

Được:

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

Đang chạy:

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

Sản xuất:

{"name":"Joe User","email":"joe@example.com","password":"mypass"}

Nếu bạn muốn thực hiện một POST POST với đối tượng JSON này:

$('#mybutton').click(function() {
    $.post('/api/user', JSON.stringify($('#myform').jsonify()));
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.