Soumettre un formulaire en JavaScript

TL;DR

form.dispatchEvent(new Event("submit", { bubbles: true, cancelable: true }))
    && form.reportValidity()
    && form.submit();

TL;RA

Le besoin était simple : inclure reCAPTCHA v3 sur des formulaires de contact. À leur soumission, on leur ajoute un token qui pourra être utilisé par le backend pour estimer la légitimité de l’interaction. Certains formulaires sont soumis par le navigateur, et d’autres via fetch. Pour être sûr d’ajouter le token en premier, on va donc écouter l’événement submit sur window pendant la phase de capture.

window.addEventListener("submit", includeReCaptchaToken, true);

Le token est obtenu via une Promise. Le temps qu’elle soit résolue il faut donc empêcher

  1. le formulaire d’être soumis par le navigateur
  2. tout écouteur de réagir à l’événement submit

On peut ensuite attendre le token et l’ajouter au formulaire, puis soumettre ce dernier.

function includeReCaptchaToken(e) {
    /* 1. */ e.preventDefault();
    /* 2. */ e.stopImmediatePropagation();

    const form = e.target;

    grecaptcha.execute("_reCAPTCHA_site_key_", { action: "contact" }).then(function(token) {
        form.querySelector("[name=recaptcha-token]").value = token;

        submitForm(form); // 🤔
    });
}

Tout formulaire dispose d’une méthode submit. Seulement… celle-ci ne déclenche pas l’événement submit, et ne valide pas le formulaire ; il va falloir le faire nous-même !

Déclencher l’événement submit

C’est la première chose à faire, car si cet événement est annulé par un écouteur on doit lui laisser le gérer. Nous allons donc créer notre version la plus fidèle de l’événement natif, qui bouillonne en plus d’être annulable :

const event = new Event("submit", {
    bubbles: true,
    cancelable: true,
});

Un événement peut être envoyé par toute cible potentielle — et donc notre formulaire — grâce à la méthode dispatchEvent. Cette dernière appelera tous les écouteurs de manière synchrone, ce qui lui permet de retourner false si au moins un a annulé l’événement. Dans ce cas, le formulaire ne doit pas être soumis et notre fonction submitForm peut retourner.

if (!form.dispatchEvent(event)) {
    return;
}

Valider le formulaire

Nous allons simplement utiliser la méthode reportValidity du formulaire. En cas d’échec, elle retournera false et signalera les erreurs à l’utilisateur. Inutile alors de soumettre le formulaire.

if (!form.reportValidity()) {
    return;
}

Soumettre le formulaire

J’espère que vous n’avez pas oublié la méthode submit du formulaire ; c’est tout ce qu’il nous reste à faire ! Empilons les blocs de code ci-dessus pour implémenter submitForm :

function submitForm(form) {
    const event = new Event("submit", {
        bubbles: true,
        cancelable: true,
    });

    if (!form.dispatchEvent(event)) {
        return;
    }

    if (!form.reportValidity()) {
        return;
    }

    form.submit();
}

Si vous préférez les one-liners, vous pouvez retrouver une version plus concise en haut de cet article.