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


Làm cách nào để chuyển đổi tất cả các phần tử 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 tôi, mà không cần phải lặp qua từng phần tử. Tôi không muốn một chuỗi, như được trả lại bởi $('#formid').serialize();và tôi cũng không muốn bản đồ được trả về bởi $('#formid').serializeArray();


1441


gốc


bởi vì đầu tiên trả về một chuỗi, giống hệt 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à thứ hai cung cấp cho bạn một mảng các đối tượng, mỗi đối tượng có một cặp giá trị tên. Tôi muốn rằng nếu tôi có một lĩnh vực có tên là "email" tôi nhận được một đối tượng mà sẽ cho phép tôi để lấy giá trị đó với obj.email. Với serializeArray (), tôi phải làm một cái gì đó như obj [indexOfElement] .value - Yisroel
@James - Câu trả lời được chấp nhận sử dụng thư viện JSON-js của D. Crockford. Đây là một ví dụ: github.com/tleese22/google-app-engine-jappstart/blob/master/src/… - Taylor Leese
@Taylor Có, tôi muốn nói câu trả lời đúng sử dụng lib của Crockford và chức năng của Tobias như sau: JSON.stringify ($ ('myForm'). SerializeObject ()) - James McCormack
@ Jonz - Có nhiều 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 cao 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 có chúng ở định dạng đối tượng để truy cập và thao tác. Ngoài ra, HTTP Post và Nhận 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
Một js tốt tôi đã xem >> github.com/marioizquierdo/jquery.serializeJSON - Bongs


Các câu trả lời:


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

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

Xem ra cho các lĩnh vực ẩn có cùng tên như đầu vào thực sự vì chúng sẽ bị ghi đè.


1543



như tvanfosson nói, tại sao lặp lại bộ sưu tập hai lần? - Yisroel
Bạn có nghĩa là "tại sao sử dụng serializeArray để có được dữ liệu ở nơi đầu tiên?" Bởi vì serializeArray đã được viết, là đơn vị được thử nghiệm trong 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. Bạn viết ít mã hơn để truy cập trực tiếp những thứ không phù hợp như các phần tử DOM, mã của bạn sẽ ổn định hơn. - Tobias Cohen
Được cảnh báo, serializeArray () sẽ không bao gồm các phần 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 tôi. 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 phần tử bị vô hiệu hóa. - Samuel Meacham
@TobiasCohen Nó không xử lý foo[bar]đầu vào kiểu như mong đợi, chưa kể đến hầu hết các giống 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 cho vấn đề này, tôi đã kết thúc bằng cách viết jQuery plugin của riêng tôi - các chi tiết trong câu trả lời tôi đã cung cấp cho câu hỏi này. - maček
@macek Tôi biết đây là một vài tháng tuổi, nhưng kể từ khi nào đã làm mảng sử dụng chỉ số không số? Không ai nên đặt tên cho một foo đầu vào [bar] và hy vọng coi nó là một mảng. Bạn đang bối rối mảng và băm? Có, [] thường được hiểu là một accessor nhưng không chỉ cho mảng. Cũng nói rằng đó là HTML hợp lệ nhưng không phải trong thông số HTML là mâu thuẫn. Có, trình duyệt có thể không bị nghẹt thở trên nó, nhưng không nhiều máy chủ web sẽ biết làm thế nào để deserialize rằng như họ sẽ một mảng. Tại sao? Bởi vì nó không có trong thông số HTML. Vì vậy, nó thực sự là không hợp lệ. - kroehre


Chuyển đổi biểu mẫu thành JSON NHƯ MỘT BOSS


Nguồn hiện tại đang bật GitHub và bower.

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


Mã sau bây giờ là không dùng nữa.

Các mã sau đây có thể làm việc 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();

Sorcery (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);

406



Vì vậy, điều đó hoạt động khá tốt. Nhưng nó bị đặ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à phải kiểm tra hasOwnProperty, nếu không mảng của bạn có bất kỳ thứ gì được gắn vào nguyên mẫu của chúng, như: {number: ["1", "3", indexOf: function () {...}]} - frontendbeauty
@frontendbeauty thực sự, toJSON là chính xác những gì spec nói nó nên được gọi là: developer.mozilla.org/en/JSON#toJSON()_method một kẻ nhầm lẫn không may. - Ryan Florence
@Marek, tôi đã làm một thử nghiệm cho ở đây trên jsfiddle. Bí quyết là đặt tên cho lựa chọn của bạn đúng cách. <select name="foo" multiple="multiple"> sẽ không hoạt động trong bất kỳ kịch bản nào. Tuy nhiên, nếu bạn sử dụng [], như trong <select name="bar[]" multiple="multiple">, Nó sẽ chỉ làm việc tốt :) - maček
Giải pháp này nên ở trên cùng vì nó đề cập đến vấn đề của các khóa lồng nhau như các tên phần tử biểu mẫu. - SquareCat
+1 Đây rõ ràng là câu trả lời tốt nhất. - Tim Seguine


Có chuyện gì với:

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

253



@ LayZee - nếu không có gì được chọn, tại sao bạn muốn nó ở phía sau của bạn? nếu bạn phải chọn một tùy chọn, hãy xác thực đầu vào trước khi tuần tự hóa. - Dementic
nếu bạn không trả lại bất cứ điều gì, tại sao bạn không sử dụng .each thay vì .map ?? - azerafati
Nó rấ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 được chọn trước nó. Bạn chắc chắn sẽ cần một số loại đầu vào phát hiện để đảm bảo nó đúng serialized. - Joshua F. Rountree
Nếu bạn muốn có một giải pháp jQuery thuần túy, bạn có thể sử dụng var form = {}; $.each($(this).serializeArray(), function (i, field) { form[field.name] = field.value || ""; }); - tfmontague
$(this).serializeArray().reduce(function(m,o){ m[o.name] = o.value; return m;}, {}) - juanpastas


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

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 viết mã 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

96



Trong coffeescript, đầu tiên nếu khối có thể được rút ngắn value = @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 phần tử gốc khỏi các khóa đã tạo. Để đạt được điều đó, tôi đã thêm một tham số mới keyMap và 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ư (name) -> name.match(/\[([^\]]+)]/)[1]. Và sau đó người ta sẽ cần phải thay đổi tất cả @name đến key, tất nhiên - Damir Zekić
@ DamirZekić, nếu phần 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 đồ lạ mắt. - maček
@ DamirZekić Đường dây này đang làm gì? if (!objectData[this.name].push)?? - kittu
@kittu Nó đang kiểm tra nếu objectData[this.name] có phương pháp đẩy (khoảng, nó là một mảng). Nếu nó là một mảng nó đẩy giá trị, nếu nó không phải là một mảng nó chuyển đổi nó thành một mảng sao cho nhiều giá trị với cùng một khóa sẽ được kết hợp với một mảng. - Daniel X Moore


Tôi thích sử dụng Array.prototype.reduce bởi vì 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ự như câu trả lời 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 bạn với một biến đối tượng bổ sung. Điểm dừng mua sắm.

LƯU Ý QUAN TRỌNG: Biểu mẫu có đầu vào có bản sao name các thuộc tính là HTML hợp lệ và thực sự là một cách tiếp cận chung. Sử dụng bất kỳ câu trả lời nào trong chuỗi 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).


49



Điều này khá thanh lịch. Nhưng đáng chú ý là array.prototype.reduce() không có sẵn trong IE8 vì nó 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 polyfill hoặc một giải pháp khác hoàn toàn. - gfullam
Đúng, nhưng thật dễ dàng để chèn lấp. Ngoài ra, nhức đầu IE8 là hầu hết Hơn nữa, nhờ 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 nữa, nhưng khi một tổ chức có 10.000 nhân viên sử dụng IE8 đi kèm ... điều đó khác. May mắn thay, Microsoft đang làm việc chăm chỉ về vấn đề đó. - Ethan Brown
Tôi làm việc cho 10.000 nhân viên đó. - gfullam
Vâng, bạn nên có những người IT 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/… - Ethan Brown
Câu trả lời chính xác! Đơn giản và ngắn gọn! - Carlos Jimenez Bermudez


Tất cả những câu trả lời này dường như trên đầu tôi. Có điều gì đó để nói về sự đơn giản. Miễn là tất cả các hình thức đầu vào của bạn có thuộc tính tên thiết lập này sẽ làm việc chỉ 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?)
});

28



+1 cho jim dandy - jenson-button-event
Tuy nhiên, 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 dandy. - Greg Pettit


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

24





Có thực sự là 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ì đó như sau đây sẽ làm việc - lưu ý rằng nó sẽ chỉ cung cấp cho bạn các yếu tố hình thức mà sẽ được trả lại thông qua một POST (phải có một tên). Đây là không được kiểm tra.

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

21



đúng, tôi rất 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 cái tên không phải là vấn đề lớn. điều này sẽ kéo tất cả các trường trong một biểu mẫu, 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 [tàn tật] nhưng tôi không nghĩ rằng nên được gửi / chọn lên. - meder omuraliev
có thể đơn giản hơn để 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 giao dịch với biểu mẫu - Yisroel
Sử dụng serializedArray sẽ làm việc, 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 mảng, sau đó trên mảng. Tôi không thấy cần thiết. - tvanfosson
Tôi sẽ điều chỉnh bộ chọn cho đã bật / tắt. - tvanfosson