web-dev-qa-db-ja.com

jQueryなしのjavascriptを使用した単純なajaxフォーム

マークアップを変更できず、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">

ヒント/チュートリアルは大歓迎です。 :)

20
calebo

以下は、他の回答のはるかに洗練されたソリューションであり、最新のブラウザーにより適しています。

私の推論は、古いブラウザーのサポートが必要な場合おそらく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以降でサポートされています。

20
Madara Uchiha

これが私があなたがやろうとしていることを正確に行うために使う気の利いた関数です:

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

Madaraの答えをさらに詳しく説明します。Chrome 47.0.2526.80(他では何もテストされていません)で動作させるために、いくつかの変更を加える必要がありました。これにより、誰かの時間を節約できるといいのですが。

このスニペットは、次の変更を加えたその回答の変更です。

  • フィルター!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);
};
3
Vince

現在、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]);
3
ZachB

戦略は、フォームをシリアル化し、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('&');
  }
}());
2
RobG

私は上記のCoomieの答えを採用し、それをラジオ/チェックボックスで機能させました。これがどれほど単純で明確かは信じられません。いくつかの例外を除いて、私はフレームワークの使用を終えました。

    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
Seth
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
Brandan

fetch を使用する最新の方法は次のとおりです。

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

IEのサポートが必要な場合は ブラウザサポート を使用し、 this polyfil を使用します

0
ferdynator