Handling submission
When a user submits a form, the browser sends it to the server and loads a new page. To check the data first, or to send it with Ajax, handle the form's submit event:
<form id="signup">
<label>Email <input id="email" name="email" type="email"></label>
<button>Sign up</button>
</form>
<p id="msg"></p>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$("#signup").on("submit", function (event) {
event.preventDefault();
const email = $("#email").val().trim();
$("#msg").text("Thanks, we will write to " + email);
console.log("submitted:", $(this).serialize());
});
</script>submitted: email=asha%40example.comAlways listen on the form, not on the button's click. Pressing Enter in a text field also submits the form, and only the submit event catches both ways. $(this).serialize() turns the form's named fields into a URL-encoded string, ready to send.
Validating before sending
A typical pattern: check each field, show messages next to the ones with problems, and only continue if everything is fine.
<style>
.error input { border-color: crimson; }
.hint { color: crimson; font-size: .9em; margin: 2px 0 8px; }
</style>
<form id="contact" novalidate>
<div class="field"><label>Name <input id="name" name="name"></label></div>
<div class="field"><label>Email <input id="cemail" name="email" type="email"></label></div>
<button>Send</button>
</form>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
function showError($input, message) {
const $field = $input.closest(".field").toggleClass("error", Boolean(message));
$field.find(".hint").remove();
if (message) $("<p>", { "class": "hint", text: message }).appendTo($field);
}
$("#contact").on("submit", function (event) {
event.preventDefault();
const name = $("#name").val().trim();
const email = $("#cemail").val().trim();
showError($("#name"), name.length < 2 ? "Please enter your full name." : "");
showError($("#cemail"), /^\S+@\S+\.\S+$/.test(email) ? "" : "Please enter a valid email address.");
const errors = $(this).find(".field.error").length;
console.log(errors ? errors + " field(s) need attention" : "form is valid, sending");
if (errors) $(this).find(".field.error input").first().trigger("focus");
});
</script>2 field(s) need attentionThe messages are added as text next to each field, and focus moves to the first field with a problem so keyboard and screen reader users land where they need to act. novalidate turns off the browser's own pop-up messages so ours are used instead; without it, the browser would check type="email" and required fields itself before our handler runs.
Browser checks are a convenience for honest users. Always validate again on the server, because anyone can send data without using your form.
change
change fires when a value is committed:
- for a
select, as soon as a new option is chosen; - for checkboxes and radios, when they are ticked or unticked;
- for text fields, when the user leaves the field after changing it (not on every key; that is
input).
<label><input id="gift" type="checkbox"> This is a gift</label>
<div id="gift-note" hidden><label>Gift message <input name="message"></label></div>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$("#gift").on("change", function () {
$("#gift-note").prop("hidden", !this.checked);
console.log("gift note shown:", this.checked);
});
</script>gift note shown: trueShowing or hiding extra fields based on a checkbox or select is the classic use of change.
focus and blur
focus fires when an element gains keyboard focus (by clicking or tabbing into it); blur fires when it loses focus. blur is a good moment to check a field, because the user has finished with it:
<label>Phone <input id="phone"></label>
<p id="phone-hint"></p>
<label>Other <input id="other"></label>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$("#phone")
.on("focus", function () { $("#phone-hint").text("Use 10 digits, no spaces."); })
.on("blur", function () {
const ok = /^\d{10}$/.test($(this).val());
$("#phone-hint").text(ok ? "" : "That does not look like a 10-digit number.");
console.log("phone ok:", ok);
});
$("#other").on("click", function () { $(this).trigger("focus"); });
</script>phone ok: falseChecking on blur is kinder than checking on every key: the user is not told off halfway through typing.
focusin and focusout
focus and blur do not bubble, so a handler on the form never hears them from its fields. focusin and focusout are the bubbling versions, so one handler on a container works for every field inside:
<style> .field.current { background: #fef9c3; } </style>
<form id="f">
<div class="field"><input id="a" placeholder="First"></div>
<div class="field"><input id="b" placeholder="Second"></div>
</form>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$("#f")
.on("focusin", "input", function () { $(this).closest(".field").addClass("current"); })
.on("focusout", "input", function () { $(this).closest(".field").removeClass("current"); });
$("#a, #b")
.on("click", function () { $(this).trigger("focus"); })
.on("focus blur focusin focusout", function (event) { console.log(event.type, this.id); });
</script>focus a
focusin a
blur a
focusout a
focus b
focusin bThe output shows the order when focus moves from the first field to the second: the old field's blur and focusout, then the new field's focus and focusin. jQuery 4 follows this standard order in every browser; jQuery 3 changed it in some cases, which is worth knowing if old code depends on it. (The handler on the form uses delegation, the subject of the next lesson.)
reset
A form's reset event fires when it is reset with a <button type="reset">. Clear your own messages there too, or they stay behind after the fields are emptied.
Common mistakes
- Handling the button's
clickinstead of the form'ssubmit. - Forgetting
preventDefault()and letting the page reload. - Using
changefor live updates on text fields; useinput. - Putting
focusorblurhandlers on a container; usefocusin/focusout. - Trusting browser validation alone.
Exercise
Make a form with a password field and a confirm field. On submit, if they differ, show a message and do not continue; if they match, log passwords match.
Show one possible answer
<form id="pw">
<input id="p1" type="password"> <input id="p2" type="password">
<button>Save</button>
<p id="pw-msg"></p>
</form>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$("#pw").on("submit", function (event) {
event.preventDefault();
if ($("#p1").val() !== $("#p2").val()) {
$("#pw-msg").text("The passwords do not match.");
return;
}
$("#pw-msg").text("");
console.log("passwords match");
});
</script>passwords matchKey points
- Handle the form's submit event, not the button's click, so pressing Enter is covered too.
- change fires when a value is committed (a select changes, a checkbox is ticked, a text field is left after editing).
- blur fires when a field loses focus, a good moment to check what was typed; focus fires when it gains focus.
- focus and blur do not bubble; focusin and focusout do, which makes them suitable for a handler on the whole form.