Comment puis-je obtenir le bouton à l'origine de l'envoi à partir de l'événement d'envoi de formulaire?

110

J'essaie de trouver la valeur du bouton d'envoi qui a déclenché l'envoi du formulaire

$("form").submit(function() {

});

Je pourrais éventuellement déclencher un événement $ ("input [type = submit]"). Click () pour chaque bouton et définir une variable, mais cela semble moins élégant que de retirer le bouton du formulaire lors de l'envoi.

chasseur
la source
2
Notez qu'il n'y a pas nécessairement un tel bouton. Un script pourrait faire l'affaire formobj.submit(). Je pense que les événements de clic sont la voie à suivre.
Jason Orendorff
1
Pour les navigateurs modernes, il existe maintenant event.submitterqui vous donne le <button>ou sur lequel vous avez <input type="submit">cliqué.
gfv

Réponses:

107

J'ai exploité document.activeElementcomme esquissé dans cette réponse: Comment obtenir l'élément ciblé avec jQuery?

$form.on('submit', function() {
    var $btn = $(document.activeElement);

    if (
        /* there is an activeElement at all */
        $btn.length &&

        /* it's a child of the form */ 
        $form.has($btn) &&

        /* it's really a submit element */
        $btn.is('button[type="submit"], input[type="submit"], input[type="image"]') &&

        /* it has a "name" attribute */
        $btn.is('[name]')
    ) {
        console.log("Seems, that this element was clicked:", $btn);
        /* access $btn.attr("name") and $btn.val() for data */
    }
});

Je profite du fait que le bouton est toujours l'élément ciblé après avoir cliqué dessus. Cela ne fonctionnera pas si vous faites un blur()droit après le clic.

@Doin a repéré un autre inconvénient. Si un utilisateur soumet le formulaire via enterdans un champ de texte, le document.activeElementn'est pas défini. Vous auriez besoin de faire attention à cela vous-même, en gérant les keypressévénements dans input[type="text"]et similaires.

Mise à jour 2017-01: Pour ma bibliothèque Hyperform, j'ai choisi de ne pas utiliser activeElementmais de capturer tous les événements qui mènent à la soumission de formulaires. Le code pour cela est sur Github.

Si vous utilisez Hyperform, voici comment accéder au bouton qui a déclenché la soumission:

$(form).on('submit', function(event) {
  var button = event.submittedVia;
});
Boldewyn
la source
1
MDN dit oui. (FF3, IE4, Chrome 2, Safari 4, Opera 9)
Boldewyn
1
Cela devrait être la réponse.
Royi Namir
2
Hmmm ... cela fonctionne-t-il si le formulaire est rempli via [Entrée]? Spec dit que cela devrait être équivalent à cliquer sur le bouton d'envoi par défaut, mais je ne suis pas sûr qu'il le laisse comme élément actif ou non.
Doin le
8
Malheureusement, vous ne pouvez pas compter uniquement suractiveElement , car le "soumissionnaire" peut être défini: A. Via l' activation de clic authentique (cliqué directement avec la souris ou le clavier Espace / Entrée); B. Par activation de clic synthétique ( buttonElement.click()ou buttonElement.dispatch(new MouseEvent(...)), sans gaing le focus); C. via la soumission implicite du formulaire (interaction du clavier avec le champ d'un autre formulaire) formElement.submit()
D.à
5
Juste une note pour garder les choses à jour. À partir de maintenant, Safari définit activeElement sur le corps du document lorsque vous cliquez sur un bouton d'envoi. J'ai rencontré ce problème sur Safari 9.1
coderkevin
35

J'ai implémenté cela et je suppose que cela fera l'affaire.

$(document).ready(function() {
    $("form").submit(function() { 

    var val = $("input[type=submit][clicked=true]").val()

    // DO WORK

});

et c'est l'événement du bouton d'envoi qui le configure

$("form input[type=submit]").click(function() {
    $("input[type=submit]", $(this).parents("form")).removeAttr("clicked");
    $(this).attr("clicked", "true");
});

Merci pour les réponses, mais ce n'est pas terriblement inélégant ...

chasseur
la source
1
Pas de crossbrowser / de boutons d'envoi multiples.
user1610743
2
Est-il garanti que l'événement de clic est déclenché avant l'événement d'envoi de formulaire? Je suggère de donner au formulaire une doNotSubmitclasse, à l'intérieur de la fonction de soumission, vérifiez si la classe n'existe pas (sinon, ne soumettez pas), à l'intérieur de l'événement click, supprimez la classe de formulaire doNotSubmitet effectuez un déclencheur $ (''. MyForm '). ('soumettre'); après avoir ajouté la valeur du bouton d'
envoi en
2
@Hafenkranich À de rares occasions sur Chrome, l'événement de clic est déclenché APRÈS l'événement d'envoi.
romanoza
@roamnoza c'est exactement ce que j'ai rencontré aussi.
Hafenkranich
2
@ j4k3 Vous avez une meilleure solution? Cette réponse a 8 ans
chasseur
10

J'ai créé un formulaire de test et en utilisant Firebug j'ai trouvé cette façon d'obtenir la valeur;

$('form').submit(function(event){
  alert(event.originalEvent.explicitOriginalTarget.value);
}); 

Malheureusement, seul Firefox prend en charge cet événement.

Dave Anderson
la source
5
IE n'a pas cette propriété (explicitOriginalTarget)
andres descalzo
1
Le bon vieil IE a tout gâché, est passé par Firebug et n'a pas pu voir d'autres valeurs d'objet à utiliser, mais il a tout simplement oublié les navigateurs alternatifs. Pas surpris d'entendre que ce n'est pas le cas, devra vérifier Chrome.
Dave Anderson
11
Seul Firefox prend en charge cet événement.
Andy E
Donc, fondamentalement, il y a quelque chose en HTML qui ne peut pas être fait dans JS ... Mozilla a décidé d'implémenter la fonctionnalité manquante, et personne n'a emboîté le pas? C'est pourquoi nous ne pouvons pas avoir de belles choses
aross
7

Il existe désormais une submitterpropriété standard dans l'événement de soumission.
Déjà implémenté dans Firefox 75 !

document.addEventListener('submit',function(e){
    console.log(e.submitter)
})

Pour les navigateurs ne le prenant pas en charge, utilisez ce polyfill :

!function(){
    var lastBtn = null
    document.addEventListener('click',function(e){
        if (!e.target.closest) return;
        lastBtn = e.target.closest('button, input[type=submit]');
    }, true);
    document.addEventListener('submit',function(e){
        if ('submitter' in e) return;
        var canditates = [document.activeElement, lastBtn];
        for (var i=0; i < canditates.length; i++) {
            var candidate = canditates[i];
            if (!candidate) continue;
            if (!candidate.form) continue;
            if (!candidate.matches('button, input[type=button], input[type=image]')) continue;
            e.submitter = candidate;
            return;
        }
        e.submitter = e.target.querySelector('button, input[type=button], input[type=image]')
    }, true);
}();
Tobias Buschor
la source
6

Voici une approche qui me semble plus propre.

Tout d'abord, pour toutes les formes:

$('form').click(function(event) {
  $(this).data('clicked',$(event.target))
});

Lorsque cet événement de clic est déclenché pour un formulaire, il enregistre simplement la cible d'origine (disponible dans l'objet événement) pour y accéder ultérieurement. Il s'agit d'un trait assez large, car il se déclenchera pour tout clic n'importe où sur le formulaire. Les commentaires d'optimisation sont les bienvenus, mais je soupçonne que cela ne causera jamais de problèmes notables.

Ensuite, dans $ ('form'). Submit (), vous pouvez demander ce qui a été cliqué pour la dernière fois, avec quelque chose comme

if ($(this).data('clicked').is('[name=no_ajax]')) xhr.abort();
Jonathan Camenisch
la source
4

Selon ce lien , l'objet Event contient un champ Event.target, qui:

Renvoie une chaîne représentant l'objet qui a déclenché l'événement.

Je viens de créer une page testant quelle est cette valeur, et il semble que cette représentation concerne le formulaire lui-même, pas le bouton sur lequel vous avez cliqué. En d'autres termes, Javascript ne fournit pas la possibilité de déterminer le bouton cliqué.

En ce qui concerne la solution de Dave Anderson , il peut être judicieux de la tester dans plusieurs navigateurs avant de l'utiliser. Il est possible que cela fonctionne bien, mais je ne peux pas dire de toute façon.

cmptrgeekken
la source
1
Le targetrenvoie la forme entière. Donc malheureusement pas utile pour détecter le bon bouton de soumission.
Hafenkranich le
Je le dis dans ma réponse, @Hafenkranich.
cmptrgeekken
Event.targetn'est pas une chaîne. C'est un EventTargetobjet, qui dans ce cas est le formulaire soumis lui-même.
Akseli le
4

Une approche propre consiste à utiliser l'événement click sur chaque bouton de formulaire. Voici un formulaire html avec des boutons d'enregistrement, d'annulation et de suppression:

<form  name="formname" action="/location/form_action" method="POST">
<input name="note_id" value="some value"/>
<input class="savenote" type="submit" value="Save"/>
<input class="cancelnote" type="submit" value="Cancel"/>
<input class="deletenote" type="submit" value="Delete" />
</form> 

Voici le jquery. J'envoie l '«action» appropriée à la même fonction de serveur en fonction du bouton sur lequel on a cliqué («enregistrer» ou «supprimer»). Si vous cliquez sur «Annuler», je recharge simplement la page.

$('.savenote').click(function(){
   var options = {
       data: {'action':'save'}
   };
   $(this).parent().ajaxSubmit(options);
   });


$('.deletenote').click(function(){
   var options = {
       data: {'action':'delete'}
   };
   $(this).parent().ajaxSubmit(options);
   });


$('.cancelnote').click(function(){
   window.location.reload(true);
   return false;
   });
user1128563
la source
3

J'ai cherché et trouvé plusieurs façons d'obtenir le bouton d' envoi name+ valueenvoyé au serveur en utilisant jQuery + AJAX. Je ne les aimais pas beaucoup ...

L'un des meilleurs était la solution du chasseur présentée ici!

Mais j'en ai écrit un autre moi-même.

Je veux partager, car c'est bon, et, comme j'avais besoin, cela fonctionne aussi avec les formulaires chargés via ajax (après document.ready):

$(document).on('click', 'form input[type=submit]', function(){
    $('<input type="hidden" />').appendTo($(this).parents('form').first()).attr('name', $(this).attr('name')).attr('value', $(this).attr('value'));
});

Facile! Lorsque le bouton d'envoi est cliqué, un champ masqué est ajouté au formulaire, en utilisant le même nameet valuedu bouton d'envoi.

EDIT: La version ci-dessous est plus facile à lire. De plus, il s'occupe de supprimer les champs cachés précédemment ajoutés (dans le cas de soumettre deux fois le même formulaire, ce qui est parfaitement possible en utilisant AJAX).

Code amélioré:

$(document).on('click', 'form input[type=submit]', function(){
    var name   = $(this).attr('name');
    if (typeof name == 'undefined') return;
    var value  = $(this).attr('value');
    var $form  = $(this).parents('form').first();
    var $input = $('<input type="hidden" class="temp-hidden" />').attr('name', name).attr('value', value);
    $form.find('input.temp-hidden').remove();
    $form.append($input);
});
J. Bruni
la source
1+ Cela l'a fait pour moi. Merci!
Lennart Rolland
Il semble que cela repose sur le <button/>partage de tous le même nameattribut. J'utiliserais une classe et j'y ferais référence dans votre .remove().
binki
@binki: non, ce n'est pas le cas. Quoi qu'il en soit, chaque développeur peut adapter la solution à ses propres besoins.
J.Bruni
jsfiddle.net/binki/d8ecv montre ce que je veux dire concernant l' nameattribut. Si le formulaire est réutilisé et contient des entrées d'envoi avec des noms différents, les anciennes entrées peuvent encombrer le formulaire.
binki
Maintenant je vois ... je vais mettre à jour ma réponse. (En fait, je n'ai pas prêté beaucoup d'attention à votre commentaire en raison du fait que vous mentionnez l' <button/>élément, alors qu'il <input type="submit" />est utilisé dans le code ...)
J. Bruni
2

J'ai essayé certains des exemples fournis, mais ils n'ont pas fonctionné pour nos besoins.

Voici un violon à montrer: http://jsfiddle.net/7a8qhofo/1/

J'ai été confronté à un problème similaire, et c'est ainsi que nous avons résolu le problème dans nos formulaires.

$(document).ready(function(){

    // Set a variable, we will fill later.
    var value = null;

    // On submit click, set the value
    $('input[type="submit"]').click(function(){
        value = $(this).val();
    });

    // On data-type submit click, set the value
    $('input[type="submit"][data-type]').click(function(){
        value = $(this).data('type');
    });

    // Use the set value in the submit function
    $('form').submit(function (event){
        event.preventDefault();
        alert(value);
        // do whatever you need to with the content
    });
});
Rudi Strydom
la source
2

( un événement )

function submForm(form,event){
             var submitButton;

             if(typeof event.explicitOriginalTarget != 'undefined'){  //
                 submitButton = event.explicitOriginalTarget;
             }else if(typeof document.activeElement.value != 'undefined'){  // IE
                 submitButton = document.activeElement;
             };

             alert(submitButton.name+' = '+submitButton.value)
}


<form action="" method="post" onSubmit="submForm(this, event); return false;">
user3126867
la source
1

vous pouvez essayer de cette façon avec "event.originalEvent.x" et "event.originalEvent.y":

<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> 
    <title>test</title>
</head>
<body>

    <form id="is_a_form">
        <input id="is_a_input_1" type="submit"><br />
        <input id="is_a_input_2" type="submit"><br />
        <input id="is_a_input_3" type="submit"><br />
        <input id="is_a_input_4" type="submit"><br />
        <input id="is_a_input_5" type="submit"><br />
    </form>

</body>
</html>
<script>
$(function(){

    $.fn.extend({
      inPosition: function(x, y) {

        return this.each(function() {

            try{
                var offset = $(this).offset();

                if ( (x >= offset.left) &&
                     (x <= (offset.left+$(this).width())) &&
                     (y >= offset.top) &&
                     (y <= (offset.top+$(this).height())) )
                {
                    $(this).css("background-color", "red");
                }
                else
                {
                        $(this).css("background-color", "#d4d0c8");
                }
                }
                catch(ex)
                {
                }

        });
      }
    }); 

    $("form").submit(function(ev) {

        $("input[type='submit']").inPosition(ev.originalEvent.x ,ev.originalEvent.y);
        return false;

    });

});
</script>
andres descalzo
la source
"yikes" ?, ça marche, ça ne marche pas, c'est utile, pas utile, ...? , Je ne parle pas bien anglais
andres descalzo
@hunter Comment puis-je voter plusieurs fois pour votre commentaire?
Tom Auger
0

jQuery ne semble pas fournir ces données sur l'événement de soumission. Il semble que la méthode que vous avez proposée soit votre meilleur pari.

Matchu
la source
0

Juste une autre solution car aucune autre ne répondait à mes exigences. L'avantage est que les clics et les touches (entrée et espace) sont détectés.

// Detects the Events
var $form = $('form');
$form.on('click keypress', 'button[type="submit"]', function (ev) {

    // Get the key (enter, space or mouse) which was pressed.
    if (ev.which === 13 || ev.which === 32 || ev.type === 'click') {

        // Get the clicked button
        var caller = ev.currentTarget;

        // Input Validation
        if (!($form.valid())) {
            return;
        }

        // Do whatever you want, e.g. ajax...
        ev.preventDefault();
        $.ajax({
            // ...
        })
    }
}

Cela a fonctionné le mieux pour moi.

Roland
la source
0

Avec un gestionnaire d'événements plus spécifiques et JQuery, votre objet événement est le bouton sur lequel vous avez cliqué. Vous pouvez également obtenir le formulaire de délégation de cet événement si nécessaire.

$('form').on('click', 'button', function (e) {
  e.preventDefault();
  var
    $button = $(e.target),
    $form = $(e.delegateTarget);
  var buttonValue = $button.val();
});

Ce Doc a tout ce dont vous avez besoin pour commencer. JQuery Doc .


la source
0

J'écris cette fonction qui m'aide

var PupulateFormData= function (elem) {
    var arr = {};
    $(elem).find("input[name],select[name],button[name]:focus,input[type='submit']:focus").each(function () {
        arr[$(this).attr("name")] = $(this).val();
    });
    return arr;

};

puis utiliser

var data= PupulateFormData($("form"));
BabiBN
la source
0

Il existe une propriété de soumissionnaire pour SubmitEvent du formulaire . Cependant, à l'heure actuelle, cela ne fonctionne pas sur Safari.

<form id="form">
    <button value="add" type="submit">Add</button>
    <button value="remove" type="submit">Remove</button>
</form>
let form = document.getElementById('form');

form.onsubmit = (event) => {
    e.preventDefault();
    console.log(e.submitter.type);
}

Une approche différente qui fonctionne sur tous les navigateurs. Cependant, vous devez vous fier à l' formélément plutôt qu'à l' eventobjet. Cela ajoute essentiellement une propriété «soumissionnaire» à l'objet d'élément de formulaire qui peut être référencé plus tard lors de l'envoi du formulaire.

<form id="form">
    <button onclick="this.form.submitter = 'add'" type="submit">Add</button>
    <button onclick="this.form.submitter = 'remove'" type="submit">Remove</button>
</form>
let form = document.getElementById('form');

form.onsubmit = (event) => {
    e.preventDefault();
    console.log(form.submitter);
}
Nur Ilyas
la source