2012-11-16 27 views
3

我需要使用JavaScript(+ Mootools)以相同類型的嵌套對象格式從PHP表單中提取數據,PHP會在表單發佈時看到它。如何使用JavaScript提取HTML表單數據?

我只是在使用谷歌搜索還是真的沒有本地或一個衆所周知的方式來實現呢?我看到很多其他人在不同的論壇上提出過相同的問題,但到目前爲止,所有人都接受了像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' 
    } 
} 
+0

看看這個http://stackoverflow.com/questions/2192091/accessing-an-array-of-html-input-text-boxes-using-jquery-or-plain-javascript – Kotzilla

+0

@Kotzilla我做知道如何分別訪問這些值。這裏的問題是讓他們進入一個乾淨和正確的嵌套對象。查看編輯。 – jpeltoniemi

回答

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 <[email protected]> 
* 
* @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; 
    } 
}); 
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; 
} 
+0

完全不是我以前的樣子。查看編輯:) – jpeltoniemi

1

from your answer。我已經作出的jquery腳本提取輸入元件,它將只與輸入一維陣列狀「輸入[字符串]」和工作「輸入[]」唯一,歡呼聲
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; 
    }); 
    });​ 
+0

感謝您的努力。不幸的是,我不使用jQuery,而是完成了我自己的版本。它非常整潔,所以如果你想,請在一分鐘內查看我的答案。仍然,+1爲你的努力:) – jpeltoniemi

0

道場有一個整潔的方法稱爲dojo.formToObject()。顧名思義,它將所有表單元素(輸入,選擇,...)轉換爲對象。例如,您可以輕鬆將其轉換爲JSON並通過AJAX通過電線發送。

+0

仍然沒有好處。像我測試過的所有其他人一樣,這個函數也不返回嵌套對象。我張貼了我自己的答案,查看了一下,看看我在做什麼。 – jpeltoniemi

相關問題