Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get the button that caused the submit from the form submit event?

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

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


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

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.


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

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.