Multiple submit buttons and JavaScript
Two sets of action can happen as per users’ desire, guided by the respective submit buttons
.
Might be a confusing user experience for a form
with input fields
, but helpful for a form
with out any input field
.
May be also helpful, for a form
with only one input field
.
An example would be, send text message or make a voice call to the users’ phone number for:
- Sending One Time Password
- Verifying the user provided phone number.
For One Time Password, phone number is already associated with users’ account, so the UI could be potentially without any input field
.
For verifying the user provided phone number, it could be part of the same UI or spread across two different UI.
The action
handler can detect which submit button
has been clicked
from the form data
, if the form was submitted via POST
or from the query parameters
, if the form was submitted via GET
method.
Here is a working (dumb) example of the above-mentioned scenario, using GET
method to greet users in Spanish or in French.
See the Pen greet by Sarbbottam Bandyopadhyay (@sarbbottam) on CodePen.
Form data
that would be passed to the action
handler, depends on the user interaction.
Below table depicts the user action
vs form data
with respect to the above (dumb) example.
user action | form data passed |
---|---|
clicks on Hola button | name=Sarbbottam&greeting=Hola |
clicks on Bonjour button | name=Sarbbottam&greeting=Bonjour |
tabs to the Hola button and presses enter in the physical keyboard |
name=Sarbbottam&greeting=Hola |
tabs to the Bonjour button and presses enter in the physical keyboard |
name=Sarbbottam&greeting=Bonjour |
while being in the name field (editable fields), presses enter in the physical keyboard or Go in the soft keyboard† |
name=Sarbbottam&greeting=Hola |
† Pressing/tapping the enter/Go
, triggers click event
on the first submit button
(the submit button that appears first in the DOM).
JavaScript and form submit
Things get interesting with introduction of JavaScript.
You might want to perform certain actions before submiting
the form
.
For example:
- Fire beacon with the
value
of thesubmit button
clicked, to the analytic system. - Modify the appearence of the
submit button
clicked
To address the above use cases, we could attach click event
listeners to each submit buttons
and on click event
perform the following actions:
- prevent the
default behavior
and stop theevent propagation
- fire beacon
- submit the form via
form.submit()
method.
Simple, isn’t it?
Not really, in the above scenario the submit button name/value
will not be passed to the form action
handler.
Please refer the below example.
See the Pen greet-user by Sarbbottam Bandyopadhyay (@sarbbottam) on CodePen.
Why the
submit button name/value
did not get pass to theaction
handler?
The form
is not being submitted in the usual manner but via form.submit()
.
As we are acting upon the click event
of the submit buttons
and not on the form submit event
, the submit button name/value
is not part of the serialized form data
.
What could we do to address this problem?
As suggested in this tweet with respect to my previous post, if we listen to the form submit event
and perform our desired action,
the submit button name/value
would be passed to the action
handler.
Wait a second, I have to fire beacons with respect to the
submit button clicked
. How do I know which button was clicked?
We can use document.activeElement
.
document.activeElement
returns the element which currently has the focus
. While clicking the submit button
we are also focusing it*.
But the form could be submitted by pressing the enter
in the physical keyboard or the Go
button in the soft keyboard. Then?
If the form
have been submitted by pressing/tapping the enter/Go
, i.e. document.activeElement.type !== 'submit'
, we could asssume the button clicked
, to be the first submit button
.
or else the button
that was clicked.
Refer the below example.
See the Pen greet-on-submit by Sarbbottam Bandyopadhyay (@sarbbottam) on CodePen.
Try the above example in a new tab/window in Chrome only. Hold on to your breath, prior trying it out in different browsers. I hear you about the browser compatibility. We will address it, please follow along.
Navigate to devtools console.
You can see the activeElemen
t is being logged and if the type is submit
its value
will also be logged.
So far, so good. Let’s try it in iOS safari. Irrespective of the button clicked, document.activeElement
always returns the body
element.
What’s going on?
As stated earlier document.activeElement
returns the element, which currently has the focus.
And in iOS Safari button
never gets the focus, neither in Chrome for iOS. FireFox/Mac and Safari/Mac follow the same pattern.
*Please refer the clicking and focus matrix for further details.
So technically we cant use this solution, for multiple submit buttons.
Cross browser solution
In my earlier proposed solution I used a hidden field
.
Listen to the click event
of each submit buttons
instead of the form submit event
.
In the event listener’s callback
- populate the value of the hidden field
with the value of the
clicked button` name
the hidden field as the name of thesubmit button clicked
.- submit the form via
form.submit()
Please refer the below example.
See the Pen greeting-js-proper by Sarbbottam Bandyopadhyay (@sarbbottam) on CodePen.
If for any reason JavaScript is not executed, the proxy-submit-button name/value
will not be passed to the form action
handler, as it does not have any name
.
But the name/value
of the submit button clicked
will be passed to the form action
handler.
If JavaScript is functional, then proxy-submit-button
’s name
and value
will be updated, with respect to the submit button
clicked, prior submitting the form
.
And thus it would be part of the serialized form data
and the submit button
clicked will not be part of the serialized form data
.
Pressing/tapping the enter/Go
, triggers click event
on the first submit button
(the submit button that appears first in the DOM).
Note:
If you are not carrying out any button specific actions
but generalized actions
you can listen to form submit
instead of listening to individual button click
.
An example of generalized action would be to disable the submit buttons on form submit, in order to prevent multiple form submission.
Please refer the below example for disabling the submit buttons and preventing multiple form submits.
See the Pen greet-on-submit-disable by Sarbbottam Bandyopadhyay (@sarbbottam) on CodePen.
Something does not look right, the submit button name/value
is not getting passed to the form action handler in the above example. Strange!!
What have we done other than disabling the submit buttons?
That exactly what we have done. We have disabled
the submit buttons
. Any disabled form fields name/value
will not be passed to the form action handler.
How do we disable the submit button then?
Event loop to the rescue. We have to carry out disabling the submit button in a setTimeout
callback, even a 0ms
would do good. setTimeout
with 0ms
will push the callback
to the end of the job queue and it will only be executed once the previous jobs have been out of the queue, i.e. the form
has been submitted
.
See the Pen greet-on-submit-disable-ok by Sarbbottam Bandyopadhyay (@sarbbottam) on CodePen.
What if I want to perform specific actions with respect to the buttons clicked along with generalized actions on form submit?
You better listen to button click event
instead of the form submit event
.
How about form validations?
Listen to the form submit event
and carry out the validation followed by form submit
on successful validation.
But if there are multiple submit buttons?
You need to ask yourself, if you really need multiple submit buttons
on a form with input fields
.
Most likely you don’t, if there are multiple input fields
.
As stated earlier, it might lead to a confusing user experience.
But if you really need it, you might have to listen to button click event
.
This has been my expereinece and comprehension so far; it would be great to know if there are other aspects.
If you have enjoyed reading this post you can follow me on twitter @sarbbottam and learn about any new posts. Opinions expressed are solely my own and do not express the views or opinions of my employer.