Plusieurs trucs qui ne sont pas vraiment des erreurs mais qui me dérangent dans ton script.
D’abord, ce troisième paramètre false dans xhr.open. Je commence à en avoir sérieusement marre de le voir partout. Je ne crie pas contre toi, ce n’est pas de ta faute. Ceux qui conseillent de s’en servir sont soit fainéants parce qu’ils ne veulent pas expliquer l’aspect asynchrone d’Ajax, soit tout simplement incompétents et devraient s’abstenir de faire des tutoriels.
Bon. La manière correcte d’ouvrir une requête Ajax, c’est :
xhr.open("POST", "server.php");
Le troisième paramètre, on l’oublie ! Sinon ce n’est pas de l’Ajax.
En plus ton script gère correctement l’asynchrone (tu utilises bien onreadystatechange) donc tu n’as rien d’autre à modifier.
Un autre truc qui me dérange c’est cette chaîne passée à setTimeout. Ça ne se voit pas forcément dès le départ, mais cette chaîne est un bout de code JavaScript… manipulé dynamiquement par du code JavaScript. Ça pose les mêmes problèmes que l’utilisation d’eval. La présence d’un seul bout de code imbriqué de ce genre, empêche un certain nombre d’optimisations à la première interprétation du code. Il est plus efficace de passer directement une fonction :
setTimeout(function () { form_a.submit(); }, 3000);
Si on faisait un bond en avant vers la modernité ? Ces deux lignes assurent une compatibilité avec IE8 et antérieurs :
1 2
| event = event || window.event;
event_target = event.target || event.srcElement; |
Regardons l’usage relatif des différents navigateurs aujourd’hui : http://caniuse.com/usage-table
On peut voir qu’IE8 fait 0.55%, et toutes versions inférieures à 9 cumulées, on atteint les 0.63%. Moins de 1% donc. Est-ce que ça en vaut la peine ? Sachant, d’ailleurs, que tu n’assures même pas une compatibilité complète avec ces versions car preventDefault n’y est pas implémenté ?
Pour des raisons d’ergonomie, il est conseillé de surveiller l’évènement submit d’un formulaire plutôt qu’un click sur son bouton submit. Plus besoin de contrôler quel élément est la cible de l’évènement : c’est forcément le form.
Allez, j’en profite pour déplacer la gestion de l’évènement vers le code JavaScript pour bien séparer les couches et avoir un code HTML tout propre.
1 2 3
| <form id="form_a" action="destination.html">
<input type="submit" id="submit_button_1" value="Submit button 1">
</form> |
1 2 3 4 5
| function submitForm(event) {
// ...
}
document.getElementById('form_a').addEventListener('submit', submitForm); |
Il est temps de s’occuper de la logique de fonctionnement. En gros, si le submit vient de l’interface utilisateur, on bloque, mais si ça vient d’Ajax, on valide. Pour symboliser ça on va utiliser un booléen isAllowed qu’on met à false par défaut. Dans la fonction de rappel de ta requête asynchrone, en cas de succès, on passe isAllowed à true, on force un submit, et on repasse à false immédiatement derrière.
Oh tiens j’en profite pour te dire qu’aujourd’hui les requêtes asynchrones ont un évènement load plus pratique à utiliser que onreadystatechange.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| var $form_a = document.getElementById("form_a");
var isAllowed = false;
function submitForm(event) {
if (!isAllowed) {
event.preventDefault();
var xhr = new XMLHttpRequest();
xhr.open("POST", "server.php");
xhr.addEventListener("load", function () {
if (200 === this.status) {
isAllowed = true;
$form_a.submit();
isAllowed = false;
}
});
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("");
}
}
$form_a.addEventListener("submit", submitForm); |
Remarque que j’ai mis une référence sur le form dans une variable globale $form_a. Tu ne peux faire ça que si le script s’exécute après que le DOM est construit. Si tu veux placer ton script dans le <head>, il faudra utiliser un évènement DOMContentLoaded.
Partager