【问题标题】:Simple ajax form using javascript no jQuery使用 javascript 没有 jQuery 的简单 ajax 表单
【发布时间】:2011-10-22 20:58:46
【问题描述】:

我正在使用我无法更改标记且无法使用 jQuery 的表单。 目前,表单将结果发布到新窗口。是否可以将其更改为 ajax 表单,以便在提交时显示结果而不更改任何标记? 将结果(标记)从结果页面拉回表单页面。

这是表单的标记。

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

非常感谢任何提示/教程。 :)

【问题讨论】:

    标签: javascript ajax forms form-submit


    【解决方案1】:

    以下是另一个答案的更优雅的解决方案,更适合现代浏览器。

    我的理由是,如果您需要对旧版浏览器的支持您很可能已经使用了像 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及以上。

    【讨论】:

    • 有些人因为性能原因不能使用jQuery,这个问题不是没有意义的。
    • 应该是“application/x-www-form-urlencoded”,而不是“application/x-form-urlencoded”。发现此问题是因为我的服务器 CORS 实现基于此标头拒绝了它。此外,由于某种原因,params 似乎出现空白,但我还没有调试过。
    • @cgag 随意编辑,或者等我今天晚些时候再做
    • 不应该是!el.disabled吗?
    • 是的,这里有一个错字。它应该是 !el.disabled。这段代码也没有在我的表单中传递 csrfmiddlewaretoken。需要调整。
    【解决方案2】:

    这是我用来做你想做的事情的一个漂亮的函数:

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

    【讨论】:

    • .elements 仅返回 FORM 的输入节点?
    • 是的,表单对象的 .elements 只返回输入节点
    • 此解决方案将发送未选中的单选按钮和复选框。
    • @AlainBeauvois — element 返回表单中的所有控件,而不仅仅是输入。
    • @Coomie 抱歉,我做不到。您可以扩展表单示例吗?它们在 onClick 中的 this 和函数中的 myself 是否有效?对不起,我不擅长 js。 this 看起来是指按钮本身
    【解决方案3】:

    现在使用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]);
    

    【讨论】:

      【解决方案4】:

      扩展 Madara 的答案:我必须进行一些更改才能使其在 Chrome 47.0.2526.80 上运行(未在其他任何设备上进行测试)。希望这可以节省一些时间。

      此 sn-p 是对该答案的修改,具有以下更改:

      • 过滤!el.disabled,
      • 在排除!checked之前检查输入类型
      • 请求类型为x-www-form-urlencoded

      结果如下:

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

      【讨论】:

      • 谢谢,这行得通。我发现了 x-www 问题,但没有发现其他两个问题。顺便说一句,这行末尾有个奇怪的“·”字符:“xhr.onload = callback.bind(xhr);·”。
      • 我喜欢这个答案。我唯一的问题是,无论是否选中复选标记,它都不会得到,毫无疑问,收音机也会有同样的问题。请参阅下面的我的答案,了解您的编辑版本,它解决了它的复选标记部分。
      【解决方案5】:

      策略是序列化表单并使用 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('&');
        }
      }());
      

      【讨论】:

        【解决方案6】:

        使用fetch 的现代方式是:

        const formData = new FormData(form);
        fetch(form.action, {
          method: 'POST',
          body: formData
        });
        

        如果需要 IE 支持,请注意 browser support 并使用 this polyfil

        【讨论】:

        • 您确定不需要其他人建议的内容类型吗?这就是我在 fetch-based npm module 中所做的
        • 可能取决于服务器端解析。我在草稿中找不到内容类型的默认值定义。所以最好明确设置它。
        【解决方案7】:
        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);
        

        };

        【讨论】:

          【解决方案8】:

          我刚刚接受了上面 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);
          

          【讨论】:

            【解决方案9】:

            这是我想出的最简单的方法。我还没有找到使用这种确切方法的示例。代码使用非提交类型按钮提交表单并将结果放入 div,如果表单无效(未填写所有必填字段),它将忽略提交操作,浏览器本身将显示哪些字段未填写填写正确。

            此代码仅适用于支持“FormData”对象的现代浏览器。

            <script>
            function ajaxSubmitForm() {
              const form = document.getElementById( "MyForm" );
              if (form.reportValidity()) {
                const FD = new FormData( form );
                var xhttp = new XMLHttpRequest();
                xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { document.getElementById("content_area").innerHTML = this.responseText; } };
                xhttp.open("POST","https://example.com/whatever.php",true);
                xhttp.send( FD );
              }
            }
            </script>
            
            <div id="content_area">
            <form id="MyForm">
              <input type="hidden" name="Token" Value="abcdefg">
              <input type="text" name="UserName" Value="John Smith" required>
              <input type="file" accept="image/jpeg" id="image_uploads" name="ImageUpload" required>
              <button type="button" onclick="ajaxSubmitForm()">
            </form>
            </div>
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-12-15
              • 2014-03-20
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多