106

There seems to be lots of info on how to submit a form using javascript, but I am looking for a solution to capture when a form has been submitted and intercept it in javascript.

HTML

<form>
 <input type="text" name="in" value="some data" />
 <button type="submit">Go</button>
</form>

When a user presses the submit button, I do not want the form to be submitted, but instead I would like a JavaScript function to be called.

function captureForm() {
 // do some stuff with the values in the form
 // stop form from being submitted
}

A quick hack would be to add an onclick function to the button but I do not like this solution... there are many ways to submit a form... e.g. pressing return while on an input, which this does not account for.

Ty

Flimm
  • 136,138
  • 45
  • 251
  • 267
mrwooster
  • 23,789
  • 12
  • 38
  • 48
  • 3
    Possible duplicate of [How to prevent form from being submitted?](http://stackoverflow.com/questions/3350247/how-to-prevent-form-from-being-submitted) – Michał Perłakowski Dec 18 '15 at 02:36

5 Answers5

113
<form id="my-form">
    <input type="text" name="in" value="some data" />
    <button type="submit">Go</button>
</form>

In JS:

function processForm(e) {
    if (e.preventDefault) e.preventDefault();

    /* do what you want with the form */

    // You must return false to prevent the default form behavior
    return false;
}

var form = document.getElementById('my-form');
if (form.attachEvent) {
    form.attachEvent("submit", processForm);
} else {
    form.addEventListener("submit", processForm);
}

Edit: in my opinion, this approach is better than setting the onSubmit attribute on the form since it maintains separation of mark-up and functionality. But that's just my two cents.

Edit2: Updated my example to include preventDefault()

Michael McTiernan
  • 5,153
  • 2
  • 25
  • 16
  • this does not work with chrome either as far as i can see using http://jsbin.com/ejoyas – Eiyrioü von Kauyf Feb 10 '13 at 17:19
  • 2
    Note that the attach event code needs to be executed AFTER the form is available in the dom. For example using `window.onload=function() { ... }` to wrap it – mplungjan Feb 26 '13 at 06:17
  • when does the `processform()` function gets called sir? –  Sep 16 '13 at 11:24
  • Not sure because I don't use IE, but I think the attachEvent parameter should be "onsubmit". – Gerard ONeill Jun 10 '15 at 19:18
  • this does not work in chrome 46, error on attaching an event, need to load the page first – tsukimi Nov 06 '15 at 02:34
  • @EiyrioüvonKauyf Your example doesn't work because you are using document.append() (non-existent) instead of document.write(). – nevelis Feb 23 '16 at 17:06
  • Should as a best practice, the event listener be added within a DOMContentLoaded event? – Jason Jun 18 '17 at 18:40
  • @Jason Allan: Yes, or use ` – cowbert Jan 06 '18 at 04:36
  • 1
    in 2017, check for addEventListener before falling back to attachEvent since IE9+ supports addEventListener. – cowbert Jan 06 '18 at 04:38
41

You cannot attach events before the elements you attach them to has loaded

It is recommended to use eventListeners - here one when the page loads and another when the form is submitted

This works since IE9:

Plain/Vanilla JS

// Should only be triggered on first page load
console.log('ho');

window.addEventListener("DOMContentLoaded", function() {
  document.getElementById('my-form').addEventListener("submit", function(e) {
    e.preventDefault(); // before the code
    /* do what you want with the form */

    // Should be triggered on form submit
    console.log('hi');
  })
});
<form id="my-form">
  <input type="text" name="in" value="some data" />
  <button type="submit">Go</button>
</form>

jQuery

// Should only be triggered on first page load
console.log('ho');

$(function() {
  $('#my-form').on("submit", function(e) {
    e.preventDefault(); // cancel the actual submit

    /* do what you want with the form */

    // Should be triggered on form submit

    console.log('hi');
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<form id="my-form">
  <input type="text" name="in" value="some data" />
  <button type="submit">Go</button>
</form>

Not recommended but will work

If you do not need more than one event handler, you can use onload and onsubmit

// Should only be triggered on first page load
console.log('ho');

window.onload = function() {
  document.getElementById('my-form').onsubmit = function() {
    /* do what you want with the form */

    // Should be triggered on form submit
    console.log('hi');
    // You must return false to prevent the default form behavior
    return false;
  }
}
    <form id="my-form">
      <input type="text" name="in" value="some data" />
      <button type="submit">Go</button>
    </form>
mplungjan
  • 169,008
  • 28
  • 173
  • 236
22

<form onSubmit="return captureForm()"> that should do. Make sure that your captureForm() method returns false.

yig
  • 329
  • 3
  • 11
kba
  • 19,333
  • 5
  • 62
  • 89
  • Follow up: Is there a way to capture a form submit with JavaScript without affecting the browser's handling of the required attribute? – Elisabeth Nov 20 '11 at 23:18
  • @Elisabeth What handling of what attribute? If you mean to not prevent the form from actually being submitted, you just need `captureForm()` to return `true` instead of `false`. – kba Nov 20 '11 at 23:30
  • The browser's handling of the "required" attribute. I do want to prevent the form from being submitted. But by returning false instead of true (or using preventDefault()), it changes how the browser handles the "required" attribute on an input element. Try it for yourself: add required to an input element, capture the submit and see if you lose the default behavior for it. – Elisabeth Nov 21 '11 at 00:43
  • I don't seem to lose default behaviour. It works fine in Chrome. You'll need to come up with an erroneous example in order for me to help. – kba Nov 21 '11 at 01:08
  • 1
    Ok, here's the form:
    and here's the code: function processForm(e) { var form = document.querySelector("form"); for (var i = 0; i < form.childNodes.length; i++) { var node = form.childNodes[i]; /* do stuff with nodes */ } /* return false; */ } Testing in opera. Uncomment the last line, required fails. (Sorry code doesn't work well in comments)
    – Elisabeth Nov 21 '11 at 05:38
  • I fail to see how `processForm()` will even be activated with that form. Additionally, Opera seems to have some bugs regarding the `required` attribute - Google it. Put an example on http://jsfiddle.net where you can actually see that your method is being executed (i.e. put in an `alert`), and give me a link. – kba Nov 21 '11 at 12:54
  • This is obtrusive JS and should be avoided. – augurone Aug 10 '15 at 18:34
  • onSubmit="return captureForm()" – mplungjan Jan 12 '17 at 17:51
4

Another option to handle all requests I used in my practice for cases when onload can't help is to handle javascript submit, html submit, ajax requests. These code should be added in the top of body element to create listener before any form rendered and submitted.

In example I set hidden field to any form on page on its submission even if it happens before page load.

//Handles jquery, dojo, etc. ajax requests
(function (send) {
    var token = $("meta[name='_csrf']").attr("content");
    var header = $("meta[name='_csrf_header']").attr("content");
    XMLHttpRequest.prototype.send = function (data) {
        if (isNotEmptyString(token) && isNotEmptyString(header)) {
            this.setRequestHeader(header, token);
        }
        send.call(this, data);
    };
})(XMLHttpRequest.prototype.send);


//Handles javascript submit
(function (submit) {
    HTMLFormElement.prototype.submit = function (data) {
        var token = $("meta[name='_csrf']").attr("content");
        var paramName = $("meta[name='_csrf_parameterName']").attr("content");
        $('<input>').attr({
            type: 'hidden',
            name: paramName,
            value: token
        }).appendTo(this);

        submit.call(this, data);
    };
})(HTMLFormElement.prototype.submit);


//Handles html submit
document.body.addEventListener('submit', function (event) {
    var token = $("meta[name='_csrf']").attr("content");
    var paramName = $("meta[name='_csrf_parameterName']").attr("content");
    $('<input>').attr({
        type: 'hidden',
        name: paramName,
        value: token
    }).appendTo(event.target);
}, false);
Vitaliy Borisok
  • 822
  • 3
  • 11
  • 21
1

Use @Kristian Antonsen's answer, or you can use:

$('button').click(function() {
    preventDefault();
    captureForm();
});
  • 7
    for anyone else doing this 2.5 years (or more) later, you need to pass the click event as a parameter to the function (as in `function(e)` and call `e.preventDefault()` – digitaljoel Nov 05 '13 at 05:10
  • Can also be captured on the "submit" event for the form, if your input[type="submit"] is used, and that puts you in the form context versus the context of the button. The callback will always have the context of the event, so you do not necessarily have to pass 'e' as an argument, you simply refer to 'event'. – augurone Aug 10 '15 at 18:34
  • 2
    This is not recommended, as submission can be triggered be a keypress. – jhpratt Dec 01 '17 at 06:00