web-dev-qa-db-fra.com

Simple formulaire ajax utilisant javascript no jQuery

Je travaille avec un formulaire pour lequel le balisage ne peut pas être modifié ni utiliser jQuery. Actuellement, le formulaire affiche les résultats dans une nouvelle fenêtre. Est-il possible de changer cela en un formulaire ajax afin que les résultats s'affichent à la place de l'envoi sans modifier le balisage?.

Voici la majoration du formulaire.

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

Tous les conseils/tutoriels sont très appréciés. :)

20
calebo

Ce qui suit est une solution beaucoup plus élégante de l’autre solution, plus adaptée aux navigateurs modernes.

Mon raisonnement est que si vous avez besoin de la prise en charge d'un navigateur plus ancien vous utilisez probablement déjà une bibliothèque telle que jQuery , ce qui rend cette question inutile.

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

Ce qui précède est pris en charge par tous les principaux navigateurs, ainsi que IE9 et les versions ultérieures.

19
Madara Uchiha

Voici une fonction astucieuse que j'utilise pour faire exactement ce que vous essayez de faire:

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

En développant la réponse de Madara: j'ai dû faire quelques modifications pour que cela fonctionne sur Chrome 47.0.2526.80 (non testé sur autre chose). Espérons que cela puisse sauver du temps à quelqu'un.

Cet extrait est une modification de cette réponse avec les modifications suivantes:

  • filtre !el.disabled,
  • vérifier le type d'entrée avant d'exclure !checked
  • Type de demande à x-www-form-urlencoded

Avec le résultat suivant:

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

De nos jours, utiliser FormData est la méthode la plus simple. Vous le construisez avec une référence à l'élément Form et il sérialise tout pour vous.

MDN a un exemple de ceci ici - en gros:

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

et si vous le voulez comme objet (JSON):

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

La stratégie consiste à sérialiser le formulaire et à envoyer les données en utilisant XHR, puis faites ce que vous voulez avec la réponse. Il existe un bon ensemble d’utilitaires et d’aide chez Matt Krus Ajax Toolbox and related Javascript Toolbox .

Si vous ne faites que sérialiser le formulaire envoyé, voici ce qui va faire l'affaire. Il peut facilement être étendu pour inclure d'autres types de contrôle de formulaire:

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

Je viens de prendre la réponse de Coomie ci-dessus et l'ai fait fonctionner pour Radio/Checkbox. Je ne peux pas croire à quel point c'est simple et clair. À quelques exceptions près, j'en ai fini avec les frameworks.

    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