如何使用javascript提取HTML表单数据?

时间:2012-11-16 11:41:16

标签: javascript forms

我需要使用javascript(+ Mootools)从HTML表单中提取数据,这种格式与PHP在发布表单时会看到的嵌套对象格式相同。

我是不是习惯谷歌搜索还是真的没有本土也没有众所周知的方法来实现这一目标?我看到很多其他人在不同的论坛上都提出了同样的问题,但到目前为止,所有人都接受了jQuery serializeArray等解决方案。

我用jsFiddle http://jsfiddle.net/7quxe/尝试了serializeArray,结果令人失望。

我之前已经为此编写了一个脚本并且它运行得很好,除非它在表单有重叠的混合键类型字段(<input name="foo[bar]" value="1"> and <input name="foo[]" value="2"时遇到了一些问题。我已经开始研究更好的版本但是当我发现自己一次又一次地重复时,我心里想:有许多伟大的js库,旨在解决许多基本的日常问题。真的可能是想要从格式正确的对象中提取表单中的数据不常见吗?

以下是我正在尝试的一个例子:

<form method="post" action="/">
    <input name="test" value="test">
    <input name="nested[a]" value="a">
    <input name="nested[b]" value="b">
    <input name="nested[c]" value="c">
    <input name="arraytest[]" value="foo">
    <input name="arraytest[]" value="foo">
    <input name="arraytest[]" value="foo">
</form>

以下是PHP将如何看待这个:

$_POST = array(
    'test' => 'test',
    'nested' => array(
        'a' => 'a',
        'b' => 'b',
        'c' => 'c',
    ),
    'arraytest' => array(
        0 => 'foo1',
        1 => 'foo2',
        2 => 'foo3'
    )
)

这就是我想在js中获得的内容:

{
    test : 'test',
    nested : {
        a : 'a',
        b : 'b',
        c : 'c'
    },
    arraytest : {       // This could also be an array ['foo1','foo2','foo3']
        0 : 'foo1',
        1 : 'foo2',
        2 : 'foo3'
    }
}

6 个答案:

答案 0 :(得分:1)

从你的答案。我已经制作了jquery脚本来提取输入元素,它只能用于输入一维数组,如“input [string]”和“input []”,欢呼
jsfiddle

<强> HTML

<h2>Form</h2>
<form action="" name="form" method="post">
  <input name="test" value="test">
  <input name="nested[a]" value="a">
  <input name="nested[b]" value="b">
  <input name="nested[c]" value="c">
  <input name="arraytest[]" value="foo">
  <input name="arraytest[]" value="foo">
  <input name="arraytest[]" value="foo">
  <p><input type="submit" /></p>
</form>

<h2>JSON output</h2>
<pre id="result"></pre>​​​​​​

<强>的jQuery

  $.fn.serializeObject = function()
  {
    var o = {}, a = this.serializeArray();
    $.each(a, function() {

      if (/(\[\]$|\[.+\]$)/.test(this.name)) {

        var match = /(.+)(\[\]|\[(.+)\])/.exec(this.name);
        if (match[3] !== undefined)
        {
          var index = match[3];
          if (o[match[1]] === undefined)
            o[match[1]] = {};

          if (o[match[1]][index] === undefined)
            o[match[1]][index] = [o[match[1]][index]];

          o[match[1]][index] = this.value || '';

        } else {
          if (o[match[1]] === undefined)
            o[match[1]] = new Array;

          o[match[1]].push(this.value || '');
        }


      } else {
        if (o[this.name] !== undefined) {
          if (!o[this.name].push) {
            o[this.name] = [o[this.name]];
          }
          o[this.name].push(this.value || '');
        } else {
          o[this.name] = this.value || '';
        }
      }

    });

    return o;
  };

  $(function() {
    $('form').submit(function() {
      $('#result').text(JSON.stringify($('form').serializeObject()));
      return false;
    });
  });​

答案 1 :(得分:0)

您可以使用form.elements对象使用直接JavaScript执行此操作。这是一个将任何表单转换为URL参数字符串的示例:

function getParameters(form) {
  var parameters = "";
  for (var x=0, y=form.elements.length; x < y; x++) {
  var field = form.elements[x];
  if (field.name && field.type !== "submit") {
    parameters += "&" + encodeURIComponent(field.name) + "=" + (field.type == "radio" || field.type == "checkbox" ? (field.checked == "checked") : encodeURIComponent(field.value));
  }
  return parameters;
}

答案 2 :(得分:0)

我对此感到痴迷,然后又痴迷于此:D

这是我的解决方案:http://jsfiddle.net/sLZZr/3/

随意借用它。如果您觉得它有用,请告诉我(不是要求,只是好奇。我的电子邮件来源:)


回答需要格式化代码,所以这里是:

/**
 * FormAccess
 * 
 * @description Manipulate data in forms and element collections. Currently only reading supported.
 *
 * @version     0.8
 *
 * @license     MIT License
 * 
 * @author      Jani Peltoniemi <jani@olio-labs.fi>
 * 
 * @copyright   2012 Jani Peltoniemi
 */


/**
* FormAccess main class
* 
*/
FormAccess = new Class({
    formElm : null,                 // The form element this instance will be linked to
    /**
    * Constructs the class and adds the quick access method "extractData" to formElm
    * 
    * @param Form element
    */
    initialize:function(formElm) {
        this.formElm = document.id(formElm);
        this.formElm.extractData = this.extractData.bind(this);
    },
    /**
    * Calls the static extractData function with the linked form's inputs
    * 
    * @returns Extracted form data in nested object
    */
    extractData : function() {
        var inputElms = this.formElm.getElements('input,textarea,select');
        return this.$constructor.extractData(inputElms);    
    }

});

/**
* FormAccess static functions
* 
* Currently only reading available. Filling forms according to data in an object will come later.
* 
*/
FormAccess.extend({
    /**
    * Extracts the data from given elements
    * 
    * Notes :
    *   - Converts empty keys to numeric. If (non-converted)numeric keys are already present, empty key becomes <largest key>+1.
    *       - Elements are handled from top to bottom. When converting empty keys between other numeric keys the largest key means largest key _up to that point_.
    *   - Inputs with empty names are not included in results.
    *   - Checkboxes' value attribute is ignored and only their checked state is included in results.
    *   - Multi-selectboxes return the selected values in an array
    * 
    * @param Selector, element or element collection - everything that $$() takes in.
    * 
    * @returns Extracted form data in nested object
    */
    extractData : function(inputElms) {
        // Normalize the input / query DOM
        inputElms = $$(inputElms);

        var that = this;
        var result = {};

        // Data from input elements is collected here for easier handling
        var inputData = [];

        // Collect inputData
        inputElms.each(function(inputElm) {
            if (!inputElm.name)
                return;
            // Explode the input name into an array path
            var path = that.parseName(inputElm.name);

            inputData.push({
                path:path,
                value:inputElm.value ? inputElm.value : '',
                elm:inputElm
            });
        });
        // Index tracking variable. Used to find next free numeric keys
        var maxIndex;
        inputData.each(function(data,i) {
            var path = data.path;

            // Last element of the path needs special treatment. Pop it out.
            var last = path.pop();

            // Working var
            var current = result;

            path.each(function(part) {

                // Assign a numeric key if the key is empty
                if (part == '') {
                    // Reset the index tracker
                    maxIndex = -1;

                    // Loop through the current position in result set
                    Object.each(current,function(val,key) {
                        // Convert key to int and make sure it is a proper number
                        var intKey = key.toInt();
                        if (intKey == key && intKey > maxIndex) {
                            // Key is greater than known largest key.
                            maxIndex = intKey;
                        }
                    });
                    // Set the key to largest found key + 1
                    part = maxIndex + 1;
                }

                // If the next position is not defined or is not an object, overwrite it.
                if (typeOf(current[part]) != 'object')
                    current[part] = {};

                // Update the position
                current = current[part];
            });

            var lastWasEmpty = false;
            // Evaluate the last part separately
            if (last == '') {
                lastWasEmpty = true;
                // Reset the index tracker
                maxIndex = -1;

                // Loop through the current position in result set
                Object.each(current,function(val,key) {
                    // Convert key to int and make sure it is a proper number
                    var intKey = key.toInt();
                    if (intKey == key && intKey > maxIndex) {
                        // Key is greater than known largest key.
                        maxIndex = intKey;
                    }
                });
                // Set the key to largest found key + 1
                last = maxIndex + 1;
            }

            // Element-specific value handling
            switch (data.elm.tagName.toLowerCase()) {
                // Case for Select, since they allow multiple selections
                case 'select':
                    if (data.elm.multiple) {
                        // A <value> = <selected> format was considered here but rejected due to long values being bad keys
                        current[last] = data.elm.getSelected().get('value');
                    } else
                        current[last] = data.value; 
                break;

                // Inputs have a couple of special cases that need to be handled differently
                case 'input':
                    switch (data.elm.type) {
                        // Only the value of the checked radiobutton is included in results.
                        // If none is checked, the result will display null
                        case 'radio':
                            // Only set the value if radiobutton is checked
                            // Otherwise check if this key is not already in results and then set it to null
                            if (data.elm.checked)
                                current[last] = data.value; 
                            else if (current[last] == undefined)
                                current[last] = null;
                        break;

                        // Checkboxes' value attribute is ignored and the checked state is included in results
                        case 'checkbox':
                            current[last] = data.elm.checked;
                        break;

                        // All others
                        default:
                                current[last] = data.value; 
                        break;
                    }
                break;

                // All other elements are handled here. 
                default:
                    current[last] = data.value; 
                break;
            }
        });
        return result;
    },
    /**
    * Explodes the name attribute.
    * 
    * Example:
    *   name="testinput[foo][bar][]"  -> ['testinput','foo','bar','']
    * 
    * @param Input name
    * 
    * @returns Exploded input name
    */
    parseName : function(name) {
        var path = [name.match(/^[^\[]*/)[0]];
        var pathRegExp = /\[(.*?)\]/g;
        var part = '';
        while (true) {
            part = pathRegExp.exec(name);
            if (part !== null)
                path.push(part[1]);
            else
                break;
        }

        return path;
    },
    /**
    * Applies the FormData object to chosen form elements.
    * 
    * If falsy argument is given, FormData is applied to all forms
    * 
    * @param Selector, element or element collection - everything that $$() takes in.
    * 
    * @returns Element collection
    */
    apply : function(elements) {
        if (!elements)
            elements = 'form';
        elements = $$(elements);

        elements.each(function(element) {
            element.formAccess = new FormAccess(element);
        });

        return elements;
    }
});

答案 3 :(得分:0)

dojo有一个称为dojo.formToObject()的简洁方法。顾名思义,它将所有表单元素(输入,选择,...)转换为对象。然后,您可以轻松地将其转换为JSON,并通过AJAX通过线路发送它,例如。

答案 4 :(得分:0)

FormData data= new FormData();

数据由您所有的表单数据组成 如果要专门使用,则需要使用

data.get("fieldName");

答案 5 :(得分:0)

group by

这是一种反应,我想你也可以使用js实现同样的事情