125

I'm trying to find the value of the submit button that triggered the form to submit

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

});

I could possibly fire a $("input[type=submit]").click() event for each button and set some variable, but that seems less elegant than some how pulling the button off of the the form on submit.

hunter
  • 62,308
  • 19
  • 113
  • 113

22 Answers22

114

I leveraged document.activeElement as sketched in this answer: How to get the focused element with 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 */
    }
});

I take advantage of the fact, that the button is always the focused element after clicking it. This will not work, if you do a blur() right after the click.

@Doin has spotted another drawback. If a user submits the form via enter in a text field, the document.activeElement is not set. You'd need to watch out for this yourself, by handling keypress events in input[type="text"] and similar.

Update 2017-01: For my library Hyperform I chose not to use activeElement but to catch all events, that lead to form submission. The code for this is on Github.

If you happen to use Hyperform, this is how you would access the button that triggered the submit:

$(form).on('submit', function(event) {
  var button = event.submittedVia;
});
Community
  • 1
  • 1
Boldewyn
  • 81,211
  • 44
  • 156
  • 212
  • Great solution. I hope it's cross browser . – Royi Namir Mar 05 '14 at 10:14
  • 1
    [MDN](https://developer.mozilla.org/en-US/docs/Web/API/document.activeElement) says yes. (FF3, IE4, Chrome 2, Safari 4, Opera 9) – Boldewyn Mar 05 '14 at 10:55
  • p.s. why did you write `$btn.is('[name]')` ? I could also put a simple submit `` – Royi Namir Mar 05 '14 at 12:06
  • You should use `.is('button[type="submit"]` instead of `.is('button,`. Also this `$btn.is('[name]')` is not always auto guaranteed. ( only for server side generated controls ) – Royi Namir Mar 05 '14 at 12:09
  • Thanks for the `[type]` note. The point of `$btn.is('[name]')` however is: When it has no `name` attribute, we have no name/value pair to submit. Hence we can skip the following process and just ignore the value of the button. – Boldewyn Mar 05 '14 at 14:24
  • 2
    Hmmm... does this work if the form is sumbitted via [Enter]? Spec says that should be equivalent to clicking the default submit button, but I'm not sure it leaves it as the active element or not. – Doin Jun 14 '14 at 05:34
  • Let's try it out: http://jsfiddle.net/boldewyn/dVzLv/ . Nope. Does not work. Here is the HTML5 spec on the topic: http://www.w3.org/html/wg/drafts/html/master/forms.html#implicit-submission . So, yes, this is a problem of my solution. You need to watch any other ``, too, for `event.which===13` keypress events, and in that case search the default submit button manually. Thanks @Doin for catching this! – Boldewyn Jun 14 '14 at 21:03
  • 1
    If you want to chime in, here is a discussion (started by me) on extending the `submit` event: http://discourse.specifiction.org/t/extend-submit-events-add-the-button-element-that-triggered-the-submit/406?u=boldewyn – Boldewyn Jun 26 '14 at 16:46
  • 9
    Sadly, **you can't rely only on `activeElement`**, because the "submitter" can be defined: A. Via _authentic click activation_ (clicked directly with mouse or keyboard Space / Enter); B. Via _synthetic click activation_ (`buttonElement.click()` or `buttonElement.dispatch(new MouseEvent(...))`, without gaing the focus); C. via _form implicitly submittion_ (keyboard interaction with other form's field) D. to none, when `formElement.submit()` – mems Sep 22 '14 at 10:32
  • 7
    Just a note to keep things current. As of right now, Safari sets activeElement to the document body when clicking on a submit button. I ran into this issue on Safari 9.1 – coderkevin May 02 '16 at 20:38
  • Also firefox on OSX wont focus the button either. The platform specific behaviour of activeElement is mentioned on https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/activeElement – adsy Nov 21 '18 at 16:05
  • It seems that at least Safari versions between 13.x and 14.x inclusive have all kinds of problems with `document.activeElement`. When you read its value and it points to `` element, you pretty much know that Safari doesn't give you the actual active element for some reason. I don't know any workaround to figure out the actual element in all cases. – Mikko Rantalainen Nov 19 '20 at 09:18
  • Thank you! Good to know. Safari often surprises with behaviour like that, unfortunately. – Boldewyn Nov 19 '20 at 13:03
33

I implemented this and I suppose it will do.

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

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

    // DO WORK

});

and this is the submit button event that sets it up

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

Thanks for the responses, but this isn't terribly inelegant...

hunter
  • 62,308
  • 19
  • 113
  • 113
  • 1
    Not crossbrowser/multiple submit buttons-capable. – user1610743 Jul 02 '14 at 10:30
  • 2
    Is it guaranteed that the click event is triggered before the form submit event? I'd suggest to give the form a `doNotSubmit` class, inside submit function check if the class is not existent (else don't submit), inside the click event remove the form class `doNotSubmit` and do a $(''.myForm').trigger('submit'); after adding the submit button value as a hidden field – Hafenkranich Jul 04 '16 at 19:28
  • 2
    @Hafenkranich On some rare occasions on Chrome the click event is triggered AFTER the submit event. – romanoza Nov 16 '16 at 11:09
  • @roamnoza thats exactly what I encountered too. – Hafenkranich Nov 16 '16 at 20:10
  • @roamnoza - makes no sense. The the click event must fire first so that the handler has an opportunity to preventDefault() – Joel Dec 15 '17 at 21:49
  • I disagree. This *is* terribly inelegant. – j4k3 Mar 23 '18 at 10:00
  • 2
    @j4k3 Got a better solution? This answer is 8 years old – hunter Mar 24 '18 at 11:04
25

There is now a standard submitter property in the submit event.
Already implemented in Firefox 75 and Chrome/Edge 81 !

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

For browsers not supporting it, use this polyfill
Note: if you target older Browsers you need to polyfill other things like closest or matches. And ensure that the polyfill is loaded before adding your submit-events.

!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];
        lastBtn = null;
        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
  • 3,075
  • 1
  • 22
  • 22
  • 8
    Note that Apple Safari still doesn't support this! – Mikko Rantalainen Nov 19 '20 at 09:19
  • Note that the above polyfill requires UA to implement Element.closest(), Element.matches() and Element.querySelector(). There's also possiblity that UA calls *your* 'submit' handler *before* the 'submit' handler in the polyfill and you don't see the `.submitter` value. – Mikko Rantalainen Nov 19 '20 at 09:23
  • Thanks Mikko, i added a note how to avoid these problems. – Tobias Buschor Nov 19 '20 at 15:28
  • The polyfill should also check that the button actually matches the form to be submitted. If the page contains e.g. two forms the button click from the first may end up being submitted by the above polyfill for the second. Also note that according to WHATWG spec, submitter may be missing if e.g. `form.submit()` has been called directly. – Mikko Rantalainen Nov 20 '20 at 16:39
  • Yes, i now reset lastBtn to null. I can't understand the behaviour of form.submit() in the spec as the submit listener is not triggered by calling form.submit() Can you point me to the spec? – Tobias Buschor Nov 20 '20 at 22:00
  • https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-form-submit step 4: "Let submitterButton be null if submitter is form. Otherwise, let submitterButton be submitter." – Mikko Rantalainen Nov 23 '20 at 09:29
11

I created a test form and using Firebug found this way to get the value;

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

Unfortunately, only Firefox supports this event.

Paul D. Waite
  • 96,640
  • 56
  • 199
  • 270
Dave Anderson
  • 11,836
  • 3
  • 58
  • 79
  • 5
    IE does not have this property (explicitOriginalTarget) – andres descalzo Jan 14 '10 at 18:03
  • 1
    Good old IE messing it up, went through Firebug and couldn't see any other object values to use but plain forgot about alternative browsers. Not surprised to hear it doesn't though, will have to check Chrome. – Dave Anderson Jan 14 '10 at 22:31
  • 12
    **Only Firefox** supports this event. – Andy E Nov 09 '11 at 16:16
  • So basically, there's something in HTML that **can not** be done in JS... Mozilla decided to implement the missing feature, and **nobody** followed suit? This is why we can't have nice things – aross Mar 06 '20 at 14:52
6

Here's an approach that seems cleaner for my purposes.

First, for any and all forms:

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

When this click event is fired for a form, it simply records the originating target (available in the event object) to be accessed later. This is a pretty broad stroke, as it will fire for any click anywhere on the form. Optimization comments are welcome, but I suspect it will never cause noticeable issues.

Then, in $('form').submit(), you can inquire what was last clicked, with something like

if ($(this).data('clicked').is('[name=no_ajax]')) xhr.abort();
Jonathan Camenisch
  • 3,472
  • 1
  • 20
  • 9
4

According to this link, the Event object contains a field Event.target, which:

Returns a string representing the object that initiated the event.

I just created a page testing out what that value is, and it appears as though that representation is for the form itself, not for the button clicked. In other words, Javascript doesn't provide the facility to determine the clicked button.

As far as Dave Anderson's solution, it might be a good idea to test that in multiple browsers before using it. It's possible that it could work fine, but I can't say either way.

Community
  • 1
  • 1
cmptrgeekken
  • 8,052
  • 3
  • 29
  • 35
  • 1
    The `target` returns the whole form. Thus unfortunately not helpful to detect the right submit button. – Hafenkranich Jul 04 '16 at 19:22
  • I say as much in my answer, @Hafenkranich. – cmptrgeekken Jul 06 '16 at 15:49
  • [`Event.target`](https://developer.mozilla.org/en-US/docs/Web/API/Event/target) is not a string. It’s an `EventTarget` object, which in this case is the submitted form itself. – akseli Apr 28 '20 at 08:33
4

There's a submitter property for form's SubmitEvent. However, as of present time, this doesn't work on 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);
}

A different approach that works across browsers. However, you have to rely on form element instead of the event object. This basically adds a 'submitter' property onto the form element object that can be referenced later on form submit.

<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
  • 121
  • 2
  • 2
4

One clean approach is to use the click event on each form button. Following is a html form with save,cancel and delete buttons:

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

Following is the jquery. I send the appropriate 'action' to the same server function depending on which button was clicked ('save' or 'delete'). If 'cancel', is clicked, I just reload the 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;
   });
3

( event )

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
  • 610
  • 5
  • 8
3

I searched and found several ways to get the submit button name + value sent to the server using jQuery + AJAX. I didn't like them very much...

One of the bests was hunter's solution presented here!

But I wrote another one myself.

I want to share, because it is good, and, as I needed, it works also with forms loaded via ajax (after 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'));
});

Simple! When the submit button is clicked, a hidden field is added to the form, using same name and value of the submit button.

EDIT: The version below is easier to read. Also, it takes care of removing previously appended hidden fields (in the case of submitting the same form twice, which is perfectly possible when using AJAX).

Improved code:

$(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
  • 20,322
  • 12
  • 75
  • 92
  • 1+ This did it for me. Thanks! – Mr. Developerdude Mar 28 '12 at 09:29
  • It looks like this relies on all ``s sharing the same `name` attribute. I would use a class and refer to that in your `.remove()`. – binki Jul 02 '13 at 14:46
  • @binki: no, it doesn't. Anyway, each developer can adapt the solution to its own needs. – J. Bruni Jul 02 '13 at 16:05
  • http://jsfiddle.net/binki/d8ecv/ shows what I mean regarding the `name` attribute. If the form is reused and contains submit inputs with different names, the old inputs can clutter the form. – binki Jul 02 '13 at 20:42
  • Now I see... I will update my answer. (In fact, I didn't pay much attention to your comment due to unrelated fact that you mention the `` element, while `` is used in the code...) – J. Bruni Jul 02 '13 at 21:52
2

I did try some of the examples provided, but they didn't work for our purposes.

Here's a fiddle to show: http://jsfiddle.net/7a8qhofo/1/

I was faced with a similar issue, and this is how we solved the issue in our forms.

$(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
  • 4,417
  • 5
  • 21
  • 30
2

Get the submitter object from the event object

You can simply get the event object when you submit the form. From that, get the submitter object. As below:

$(".review-form").submit(function (e) {
        e.preventDefault(); // avoid to execute the actual submit of the form.

        let submitter_btn = $(e.originalEvent.submitter);
        
        console.log(submitter_btn.attr("name"));
}

I have explained in detail in this answer here: (https://stackoverflow.com/a/66334184/11320178)
Let me know if you have any doubts.

1

you can try this way with "event.originalEvent.x" and "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
  • 14,887
  • 13
  • 64
  • 115
0

jQuery doesn't seem to provide that data on the submit event. Looks like the method you proposed is your best bet.

Matchu
  • 83,922
  • 18
  • 153
  • 160
0

Just another solution since no other met my requirements. The advantage is, that click and keypress (enter and space) are detected.

// 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({
            // ...
        })
    }
}

This worked best for me.

roland
  • 900
  • 12
  • 25
0

With a more specific event handler and JQuery, your event object is the button clicked. You can also get the delegating form from this event if needed.

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

This Doc has everything you need to get started. JQuery Doc.

0

I write this function that helps me

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;

};

and then Use

var data= PupulateFormData($("form"));
BabiBN
  • 91
  • 1
  • 2
0

In working with web components where form elements are in the shadowRoot I adapted Tobias Buschor's excellent polyfill as follows to work in the following way via an imported module. Note this only provides compatibility in evergreen clients--edge, safari, chrome, firefox. Also, as noted by Mikko Rantalainen, this doesn't follow (and I/we can update at some point to follow) https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-form-submit

if( !('SubmitEvent' in self && 'submitter' in SubmitEvent.prototype) ){
// polyfill SubmitEvent.submitter (a Safari issue as-of 2021)
// https://developer.mozilla.org/docs/Web/API/SubmitEvent
    const submitter = Symbol.for('submitter');
    Event[ submitter ] = null;
    const submitterSelector = 'input[type=submit], input[type=image], input[type=button], button';

    Object.defineProperty(Event.prototype, 'submitter', {
        get: function(){
            if('submit' === this.type){
                let node = Event[ submitter ];
                const form = this.target;
                if(!node || !form.contains(node)){
                    node = form.querySelector(submitterSelector);
                }
                // always return a node, default as though form.submit called
                return node || form;
            }
            return undefined;
        },
        set: function(value){
            if('submit' === this.type){
                this.submitter = value;
            }
        }
    });
    self.addEventListener('click', function polyfill_SubmitEvent_submitter_click(event){
        const node = event.composedPath()[0];
        const closest = node.closest?.(submitterSelector) ?? null;
        Event[ submitter ] = closest;
    }, true);
}
jimmont
  • 2,304
  • 1
  • 27
  • 29
0

$(document).ready(function() {
    $( "form" ).submit(function (event) {
        // Get the submit button element
        let submit_button =  event.handleObj;
        //submit button has the object of the use clicked button
    });
}
Jiffin
  • 1
  • 1
  • 2
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 05 '21 at 16:48
0

You can obtain the button id of the following HTML code:

<form id="theForm" action="" method="POST">
  <button name="sbtn" id="sbtn" value="Hey button" type="submit">Submit</button>
</form>

using the following JavaScript (leveraging on the .val() attribute):

$('#theForm').on('click', 'button', function (e) {
  e.preventDefault();
  var
    $button = $(e.target),
    $form = $(e.delegateTarget);
  var buttonValue = $button.val();
});
Mario Petrovic
  • 7,500
  • 14
  • 42
  • 62
George m
  • 75
  • 2
  • 4
0

Without jquery

submit(e){
    console.log(e.nativeEvent.submitter)
}
Abraham
  • 12,140
  • 4
  • 56
  • 92
0

I was finally able to find a complete and easy answer to the question : How can I get the button that caused the submit from the form submit event ?

I'll give you a simple example :

CODE HTML : The form

<form id="myForm" enctype="multipart/form-data" method="post">

  ...
  all input, select, textarea ...
  ....

  <button id="bt1" value="add" type="submit">Add</button>
  <button id="bt2" value="back" type="submit">Back</button>
  <button id="bt3" value="remove" type="submit">Remove</button>
  <button id="bt4" value="register" type="submit">Register</button>
</form>

CODE JAVASCRIPT : event listener and actions

var myFctSubmit = function(event){
   var myTarget = event.target || event.srcElement;
   var myButton = event.originalEvent.submitter;

   var balise_form = $(myTarget).attr('id');
   var balise_button = $(myButton).attr('id');

   //Now you know the button and
   //you can apply the script you want...
   //here in this exemple :
   //balise_form = myForm
   //balise_button = {button that you click}

}

$('#myForm').bind('submit',myFctSubmit);

Therefore, the solution to this problem is to fetch the following element :

event.originalEvent.submitter

Good luck everyone