HTML Forms: How (and Why) to Prevent Double Form Submissions – Bram.us
I can see how this would be good to have fixed at the browser level.
I can see how this would be good to have fixed at the browser level.
I’m a big fan of HTML5’s datalist
element and its elegant design. It’s a way to progressively enhance any input
element into a combobox.
You use the list
attribute on the input
element to point to the ID of the associated datalist
element.
<label for="homeworld">Your home planet</label>
<input type="text" name="homeworld" id="homeworld" list="planets">
<datalist id="planets">
<option value="Mercury">
<option value="Venus">
<option value="Earth">
<option value="Mars">
<option value="Jupiter">
<option value="Saturn">
<option value="Uranus">
<option value="Neptune">
</datalist>
It even works on input type="color"
, which is pretty cool!
The most common use case is as an autocomplete widget. That’s how I’m using it over on The Session, where the datalist
is updated via Ajax every time the input is updated.
But let’s stick with a simple example, like the list of planets above. Suppose the user types “jup” …the datalist will show “Jupiter” as an option. The user can click on that option to automatically complete their input.
It would be handy if you could automatically submit the form when the user chooses a datalist option like this.
Well, tough luck.
The datalist
element emits no events. There’s no way of telling if it has been clicked. This is something I’ve been trying to find a workaround for.
I got my hopes up when I read Amber’s excellent article about document.activeElement
. But no, the focus stays on the input when the user clicks on an option in a datalist.
So if I can’t detect whether a datalist has been used, this best I can do is try to infer it. I know it’s not exactly the same thing, and it won’t be as reliable as true detection, but here’s my logic:
Here’s how that translates into DOM scripting code:
document.querySelectorAll('input[list]').forEach( function (formfield) {
var datalist = document.getElementById(formfield.getAttribute('list'));
var lastlength = formfield.value.length;
var checkInputValue = function (inputValue) {
if (inputValue.length - lastlength > 1) {
datalist.querySelectorAll('option').forEach( function (item) {
if (item.value === inputValue) {
formfield.form.submit();
}
});
}
lastlength = inputValue.length;
};
formfield.addEventListener('input', function () {
checkInputValue(this.value);
}, false);
});
I’ve made a gist with some added feature detection and mustard-cutting at the start. You should be able to drop it into just about any page that’s using datalist. It works even if the options in the datalist are dynamically updated, like the example on The Session.
It’s not foolproof. The inference relies on the difference between what was previously typed and what’s autocompleted to be more than one character. So in the planets example, if someone has type “Jupite” and then they choose “Jupiter” from the datalist, the form won’t automatically submit.
But still, I reckon it covers most common use cases. And like the datalist
element itself, you can consider this functionality a progressive enhancement.
Dave uses just a smidgen of JavaScript to whip HTML5’s native form validation into shape.
Instead of being prescriptive about error messaging, we use what the browser natively gives us.