2011-08-09 73 views
17

我正在使用一種表單,我無法更改標記&無法使用jQuery。 當前表單將結果發佈到新窗口。是否有可能將其更改爲ajax表單,以便在提交時顯示結果而不改變任何標記? 將結果(標記)從結果頁面拉回到表單頁面。簡單的Ajax形式使用JavaScript沒有jQuery

以下是窗體的標記。

<form class="form-poll" id="poll-1225962377536" action="/cs/Satellite" target="_blank"> 
<div class="form-item"> 
    <fieldset class="form-radio-group"> 
     <legend><span class="legend-text">What mobile phone is the best?</span></legend> 
       <div class="form-radio-item"> 
        <input type="radio" class="radio" value="1225962377541" name="option" id="form-item-1225962377541"> 
        <label class="radio" for="form-item-1225962377541"> 
         <span class="label-text">iPhone</span> 
        </label> 
       </div><!-- // .form-radio-item --> 
       <div class="form-radio-item"> 
        <input type="radio" class="radio" value="1225962377542" name="option" id="form-item-1225962377542"> 
        <label class="radio" for="form-item-1225962377542"> 
         <span class="label-text">Android</span> 
        </label> 
       </div><!-- // .form-radio-item --> 
       <div class="form-radio-item"> 
        <input type="radio" class="radio" value="1225962377543" name="option" id="form-item-1225962377543"> 
        <label class="radio" for="form-item-1225962377543"> 
         <span class="label-text">Symbian</span> 
        </label> 
       </div><!-- // .form-radio-item --> 
       <div class="form-radio-item"> 
        <input type="radio" class="radio" value="1225962377544" name="option" id="form-item-1225962377544"> 
        <label class="radio" for="form-item-1225962377544"> 
         <span class="label-text">Other</span> 
        </label> 
       </div><!-- // .form-radio-item --> 
    </fieldset> 
</div><!-- // .form-item --> 
<div class="form-item form-item-submit"> 
    <button class="button-submit" type="submit"><span>Vote now</span></button> 
</div><!-- // .form-item --> 
<input type="hidden" name="c" value="News_Poll"> 
<input type="hidden" class="pollId" name="cid" value="1225962377536"> 
<input type="hidden" name="pagename" value="Foundation/News_Poll/saveResult"> 
<input type="hidden" name="site" value="themouth"> 

任何提示/教程十分讚賞。 :)

回答

2

策略是序列化表單並使用XHR發送數據,然後根據響應做你想要的。 Matt Krus的Ajax Toolbox和相關的Javascript Toolbox有一套很好的實用程序和幫助。

如果您只是對發佈的表單進行序列化,那麼以下內容就可以實現。它可以很容易地擴展到其他形式的控制類型:

var serialiseForm = (function() { 

    // Checkboxes that have already been dealt with 
    var cbNames; 

    // Return the value of a checkbox group if any are checked 
    // Otherwise return empty string 
    function getCheckboxValue(cb) { 
    var buttons = cb.form[cb.name]; 
    if (buttons.length) { 
     for (var i=0, iLen=buttons.length; i<iLen; i++) { 
     if (buttons[i].checked) { 
      return buttons[i].value; 
     } 
     } 
    } else { 
     if (buttons.checked) { 
     return buttons.value; 
     } 
    } 
    return ''; 
    } 

    return function (form) { 
    var element, elements = form.elements; 
    var result = []; 
    var type; 
    var value = ''; 
    cbNames = {}; 

    for (var i=0, iLen=elements.length; i<iLen; i++) { 
     element = elements[i]; 
     type = element.type; 

     // Only named, enabled controls are successful 
     // Only get radio buttons once 
     if (element.name && !element.disabled && !(element.name in cbNames)) { 

     if (type == 'text' || type == 'hidden') { 
      value = element.value; 

     } else if (type == 'radio') { 
      cbNames[element.name] = element.name; 
      value = getCheckboxValue(element); 

     } 
     } 

     if (value) { 
     result.push(element.name + '=' + encodeURIComponent(value)); 
     } 
     value = ''; 

    } 
    return '?' + result.join('&'); 
    } 
}()); 
12

下面是我用做的正是一個極好的功能,你想要做什麼:

HTML:

<form action="/cs/Satellite">...</form> 
<input type="button" value="Vote now" onclick="javascript:AJAXPost(this)"> 

JS :

function AJAXPost(myself) { 
    var elem = myself.form.elements; 
    var url = myself.form.action;  
    var params = ""; 
    var value; 

    for (var i = 0; i < elem.length; i++) { 
     if (elem[i].tagName == "SELECT") { 
      value = elem[i].options[elem[i].selectedIndex].value; 
     } else { 
      value = elem[i].value;     
     } 
     params += elem[i].name + "=" + encodeURIComponent(value) + "&"; 
    } 

    if (window.XMLHttpRequest) { 
     // code for IE7+, Firefox, Chrome, Opera, Safari 
     xmlhttp=new XMLHttpRequest(); 
    } else { 
     // code for IE6, IE5 
     xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); 
    } 

    xmlhttp.open("POST",url,false); 
    xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 
    xmlhttp.setRequestHeader("Content-length", params.length); 
    xmlhttp.setRequestHeader("Connection", "close"); 
    xmlhttp.send(params); 

    return xmlhttp.responseText; 
} 
+1

'.elements'爲'只返回輸入節點FORM'? –

+0

是的。表單對象的.elements只返回輸入節點 –

+0

該解決方案將發送未經檢查的單選按鈕和複選框。 –

17

以下是其他答案的更優雅的解決方案,更適合現代瀏覽器。

我的推理是,如果您需要支持較舊的瀏覽器,您已經很可能使用類似jQuery的庫,從而使此問題變得毫無意義。

/** 
* Takes a form node and sends it over AJAX. 
* @param {HTMLFormElement} form - Form node to send 
* @param {function} callback - Function to handle onload. 
*        this variable will be bound correctly. 
*/ 

function ajaxPost (form, callback) { 
    var url = form.action, 
     xhr = new XMLHttpRequest(); 

    //This is a bit tricky, [].fn.call(form.elements, ...) allows us to call .fn 
    //on the form's elements, even though it's not an array. Effectively 
    //Filtering all of the fields on the form 
    var params = [].filter.call(form.elements, function(el) { 
     //Allow only elements that don't have the 'checked' property 
     //Or those who have it, and it's checked for them. 
     return typeof(el.checked) === 'undefined' || el.checked; 
     //Practically, filter out checkboxes/radios which aren't checekd. 
    }) 
    .filter(function(el) { return !!el.name; }) //Nameless elements die. 
    .filter(function(el) { return el.disabled; }) //Disabled elements die. 
    .map(function(el) { 
     //Map each field into a name=value string, make sure to properly escape! 
     return encodeURIComponent(el.name) + '=' + encodeURIComponent(el.value); 
    }).join('&'); //Then join all the strings by & 

    xhr.open("POST", url); 
    // Changed from application/x-form-urlencoded to application/x-form-urlencoded 
    xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 

    //.bind ensures that this inside of the function is the XHR object. 
    xhr.onload = callback.bind(xhr); 

    //All preperations are clear, send the request! 
    xhr.send(params); 
} 

上述功能在所有主流瀏覽器和IE9及以上版本均支持。

+4

有些人因爲性能原因不能使用jQuery,這個問題並不是毫無意義的。 – JmJ

+0

這應該是「application/x-www-form-urlencoded」,而不是「application/x-form-urlencoded」。發現這個問題是因爲我的服務器CORS實現基於這個頭來拒絕它。 此外,由於某些原因,params似乎是空白的,但我沒有調試過。 – cgag

+0

@cgag可以自由編輯,或者等我今天晚些再做 –

3

擴大對Madara的答案:我不得不做一些改變,使其在Chrome 47.0.2526.80(未在其他任何測試)工作。希望這可以節省一些時間。

這個片段是答案具有以下變化的變形例:不含!checked

  • 請求類型來x-www-form-urlencoded
  • 隨着前

    • 濾波器!el.disabled
    • 輸入的檢查類型結果如下:

      function ajaxSubmit(form, callback) { 
          var xhr = new XMLHttpRequest(); 
          var params = [].filter.call(form.elements, function (el) {return !(el.type in ['checkbox', 'radio']) || el.checked;}) 
          .filter(function(el) { return !!el.name; }) //Nameless elements die. 
          .filter(function(el) { return !el.disabled; }) //Disabled elements die. 
          .map(function(el) { 
           return encodeURIComponent(el.name) + '=' + encodeURIComponent(el.value); 
          }).join('&'); //Then join all the strings by & 
          xhr.open("POST", form.action); 
          xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 
          xhr.onload = callback.bind(xhr); 
          xhr.send(params); 
      }; 
      
    +0

    謝謝,這工作。我發現了x-www問題,但沒有發現其他兩個問題。順便提一句,在這行末尾有一個奇怪的「·」字符:「xhr.onload = callback.bind(xhr);」「。 – cgag

    +0

    我很喜歡這個答案。我唯一的問題是,如果勾選了複選標記,它就不會得到,毫無疑問,它將與廣播有相同的問題。查看我的答案,下面列出瞭解決您的編輯部分的編輯版本。 – Brandan

    0
    function ajaxSubmit(form, callback) { 
    var xhr = new XMLHttpRequest(); 
    var params = [].filter.call(form.elements, function (el) {return !(el.type in ['checkbox', 'radio']) || el.checked;}) 
    .filter(function(el) { return !!el.name; }) //Nameless elements die. 
    .filter(function(el) { return !el.disabled; }) //Disabled elements die. 
    .map(function(el) { 
        if (el.type=='checkbox') return encodeURIComponent(el.name) + '=' + encodeURIComponent(el.checked); 
        else return encodeURIComponent(el.name) + '=' + encodeURIComponent(el.value); 
    }).join('&'); //Then join all the strings by & 
    xhr.open("POST", form.action); 
    xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 
    xhr.onload = callback.bind(xhr); 
    xhr.send(params); 
    

    };

    0

    我剛剛拿着Coomie的回答,並且使它適用於Radio/Checkboxes。我無法相信這是多麼簡單明瞭。除了少數例外,我完成了使用框架。

    var params = ""; 
        var form_elements = form.elements; 
        for (var i = 0; i < form_elements.length; i++) 
        { 
         switch(form_elements[i].type) 
         { 
          case "select-one": 
          { 
           value = form_elements[i].options[form_elements[i].selectedIndex].value; 
          }break; 
          case "checkbox": 
          case "radio": 
          { 
           if (!form_elements[i].checked) 
           { 
            continue; // we don't want unchecked data 
           } 
           value = form_elements[i].value; 
          }break; 
          case "text" : 
          { 
           value = form_elements[i].value;     
          }break; 
    
         } 
    
         params += encodeURIComponent(form_elements[i].name) + "=" + encodeURIComponent(value) + "&"; 
        } 
    
    
    
        var xhr = new XMLHttpRequest();  
        xhr.open('POST', "/api/some_url"); 
        xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); 
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 
        xhr.onreadystatechange = function() { 
         if (xhr.readyState == 4) { 
          if (xhr.status == 200) 
          { 
    
           console.log("xhr.responseText"); 
          } 
          else 
          { 
           console.log("Error! Status: ", xhr.status, "Text:", xhr.responseText); 
          } 
         } 
        }; 
    
        console.log(params); 
        xhr.send(params); 
    
    0

    現在使用FormData是最簡單的方法。您可以使用對Form元素的引用來構造它,並且它會爲您序列化所有內容。

    MDN有這個here的例子 - 大致爲:

    const form = document.querySelector("#debarcode-form"); 
    form.addEventListener("submit", e => { 
        e.preventDefault(); 
        const fd = new FormData(form); 
        const xhr = new XMLHttpRequest(); 
        xhr.addEventListener("load", e => { 
         console.log(e.target.responseText); 
        }); 
        xhr.addEventListener("error", e => { 
         console.log(e); 
        }); 
        xhr.open("POST", form.action); 
        xhr.send(fd); 
    }); 
    

    ,如果你想把它當作一個對象(JSON):

    const obj = {}; 
    [...fd.entries()].forEach(entry => obj[entry[0]] = entry[1]);