Form validation
Introduction
Section titled βIntroductionβThe first rule of web development is simple: never trust any user input.
This is because users can enter anything they want into a form field, and itβs up to you to make sure that the data is valid and safe to use.
This tutorial will walk you through how to validate user input in a sign-up form for Harmony Music Academy.
1. Presence checking
Section titled β1. Presence checkingβThe simplest form of validation is to check if a field is empty or not. This is known as presence checking.
In our sign-up form, we want to make sure that the user has entered their email address, level, and hours per week.
Checking for empty fields
Section titled βChecking for empty fieldsβLetβs start by seeing what happens when we submit the form without entering any data.
-
If you have been following the steps in the previous tutorial on Capturing Form Data, you should already have the following code inside your
index.js
file:index.js // Capture user's input on form submissionlet form = document.querySelector("form");form.addEventListener("submit", function (event) {event.preventDefault();// Store the user's email address as userEmail (string/text)let userEmail = document.querySelector("#email").value;// Store the user's level as userLevel (string/text)let userLevel = document.querySelector("#level").value;// Store the user's hours of study as userHours (number)let userHours = document.querySelector("#hoursPerWeek").value;console.log({ userEmail, userLevel, userHours });});7 collapsed lines// Validate the user's input// Check if the user has selected a level// Check if the user has provided an email address// Check if the user has specified at least one hour of study// Check if the number of hours requested is within the allowed range// Calculate the total cost// Display the total cost to the user -
With this code in place, start your application server in the usual way.
-
In your browser, open up the dev tools, and navigate to the βConsoleβ tab.
-
Submit the form without entering any data. You should see the following output in the console:
As you can see, the
userEmail
anduserHours
values are empty strings, whileuserLevel
is string that reads'basic'
.{ userEmail: "", userLevel: "basic", userHours: "" }
Letβs spend a moment to understand where these values are coming from.
Checking for empty fields
Section titled βChecking for empty fieldsβNow that we know where our form values are coming from, letβs think how we can add a validation check that ensures that the user has entered an email address.
-
Inside
index.js
, just above theconsole.log()
statement, add a conditional check like so:index.js // Capture user's input on form submissionlet form = document.querySelector("form");form.addEventListener("submit", function (event) {event.preventDefault();// Store the user's email address as userEmail (string/text)let userEmail = document.querySelector("#email").value;// Store the user's level as userLevel (string/text)let userLevel = document.querySelector("#level").value;// Store the user's hours of study as userHours (number)let userHours = document.querySelector("#hoursPerWeek").value;// Validate the user's input// Check if the user has provided an email addressif (userEmail === "") {alert("Please enter your email address.");return;}console.log({ userEmail, userLevel, userHours });}); -
Save your changes, and head back over to your browser.
Make sure your devtools console is still open, and try submitting an empty form again.
This time, you should see an alert message that says βPlease enter your email address.β
-
Did you notice something else as well? The
console.log()
statement is no longer executed when the email field is empty.Can you work out why?
Solution
Section titled βSolutionβThis is because the
return
statement inside theif
block stops the function from executing any further.if (userEmail === "") {alert("Please enter your email address.");return;}Any time you see a
return
statement inside a function, it means that the function will stop executing the code inside it at that point andreturn
whatever value we have told it to.(In this case, the function returns
undefined
, because we havenβt specified a value to return.)Because of this, the
console.log()
statement is never reached when the email field is empty.This behaviour is useful because it allows us to stop the computer processing data unnecessarily if any of the fields are empty.
Click to reveal -
Now that we have a check in place for the email field, letβs add similar ones to validate the other form fields.
Move the next two steps of your comment plan up inside the event handler function:
index.js // Capture user's input on form submissionlet form = document.querySelector("form");form.addEventListener("submit", function (event) {8 collapsed linesevent.preventDefault();// Store the user's email address as userEmail (string/text)let userEmail = document.querySelector("#email").value;// Store the user's level as userLevel (string/text)let userLevel = document.querySelector("#level").value;// Store the user's hours of study as userHours (number)let userHours = parseInt(document.querySelector("#hoursPerWeek").value);// Validate the user's input// Check if the user has provided an email addressif (userEmail === "") {alert("Please enter your email address.");return;}// Check if the user has selected a level// Check if the number of hours requested is within the allowed rangeconsole.log({ userEmail, userLevel, userHours });});// Check if the user has selected a level// Check if the number of hours requested is within the allowed rangeCan you add checks to ensure that the
userLevel
anduserHours
fields are not submitted as empty strings? π€Expected behaviour
Section titled βExpected behaviourβ- If the user has submitted an empty string for either
userHours
oruserLevel
, display an alert message to prompt them to enter the required information. - The function should not continue to log the form data to the console if
userEmail
,userHours
oruserLevel
are empty. - If there are values for each of the fields, the form data should be logged to the console as before.
Solution
Section titled βSolutionβTo add checks for the
userHours
anduserLevel
fields, you can follow the same pattern as the check for theuserEmail
field.index.js // Capture user's input on form submissionlet form = document.querySelector("form");form.addEventListener("submit", function (event) {8 collapsed linesevent.preventDefault();// Store the user's email address as userEmail (string/text)let userEmail = document.querySelector("#email").value;// Store the user's level as userLevel (string/text)let userLevel = document.querySelector("#level").value;// Store the user's hours of study as userHours (number)let userHours = parseInt(document.querySelector("#hoursPerWeek").value);// Validate the user's input// Check if the user has provided an email addressif (userEmail === "") {alert("Please enter your email address.");return;}// Check if the user has selected a levelif (userLevel === "") {alert("Please select a level of study");return;}// Check if the user has specified at least one hour of studyif (userHours === "") {alert("Please enter at least one hour of tuition.");return;}console.log({ userEmail, userLevel, userHours });});// Check if the user has selected a level// Check if the number of hours requested is within the allowed range// Calculate the total cost// Display the total cost to the userClick to reveal - If the user has submitted an empty string for either
2. Content validation
Section titled β2. Content validationβPresence checking is one thing, but we also need to make sure that the data entered by the user is valid.
Letβs start by checking if the user has entered a valid email address.
Checking for valid email addresses
Section titled βChecking for valid email addressesβThis is actually surprising easy!
-
Open
index.html
-
Locate the input field for the userβs email address.
It should be around line 17, and look like this:
index.html <inputid="email"name="email"type="text"class="form-input"placeholder="Your email"/> -
The
type
attribute of the input field is set totext
, which means that it accepts any kind of text input.All we need to do is change this to
email
:index.html <inputid="email"name="email"type="email"class="form-input"placeholder="Your email"/> -
With this in place, if you submit a value in the email field that is not a valid email address, the browser will automatically display an error message.
Checking for valid hours
Section titled βChecking for valid hoursβOne surprisingly tricky check is to ensure that users must enter a positive integer for the number of hours.
-
Open
index.js
-
Before we can check if the number is positive or not, we need to convert the value of
userHours
to a number.This is because the
value
of an input field is always a string, even if the HTML input field is of typenumber
.To convert the value to a number, we can use the built-in JavaScript
parseInt()
function.Remove the line highlighted in red below, and replace it with the code highlighted in green:
index.js form.addEventListener("submit", function (event) {event.preventDefault();let userEmail = document.querySelector("#email").value;let userLevel = document.querySelector("#level").value;let userHours = document.querySelector("#hoursPerWeek").value;let userHours = document.querySelector("#hoursPerWeek").value;let userHours = parseInt(document.querySelector("#hoursPerWeek").value);12 collapsed linesif (userEmail === "") {alert("Please enter your email address.");return;}if (userHours === "") {alert("Please enter at least one hour of tuition.");return;}console.log({ userEmail, userLevel, userHours });}); -
Now we can check whether the actual value is a positive number. But this is where it gets tricky.
Our previous solution of checking if the value is an empty string will no longer work, because
parseInt()
always returns a number, even if the user enters an empty string.The problem is that an empty string cannot be converted to a number, so
parseInt()
will instead returnNaN
(Not a Number) instead.As a result, our previous presence check which looks at whether
userHours === ""
will no longer work, so we need to update it.Remove the previous check, and modify it as follows:
index.js // Capture user's input on form submissionlet form = document.querySelector("form");form.addEventListener("submit", function (event) {event.preventDefault();20 collapsed lines// Store the user's email address as userEmail (string/text)let userEmail = document.querySelector("#email").value;// Store the user's level as userLevel (string/text)let userLevel = document.querySelector("#level").value;// Store the user's hours of study as userHours (number)let userHours = parseInt(document.querySelector("#hoursPerWeek").value);// Validate the user's input// Check if the user has provided an email addressif (userEmail === "") {alert("Please enter your email address.");return;}// Check if the user has selected a levelif (userLevel === "") {alert("Please select a level of study");}// Check if the user has specified at least one hour of studyif (userHours === "") {if (isNaN(userHours) || userHours < 1) {alert("Please enter at least one hour of tuition.");return;}console.log({ userEmail, userLevel, userHours });});// Check if the number of hours requested is within the allowed range// Calculate the total cost// Display the total cost to the user -
Save your changes, and head across to your browser.
Try submitting the form with an empty hours field, and then again with
0
or a negative number.In each case, should see the following alert message:
Validate level and hours
Section titled βValidate level and hoursβThere are at least two more validation checks we need to consider:
- Is the level of study selected by the user valid?
- Is the number of hours requested within the allowed range for the level they have chosen (e.g., between 1 and 10 hours)?
Can you implement these two checks in your code?
Discuss this with a partner or in a group first, and then try to implement the checks in your code.
Are there any other validation checks that you identified while planning your logic algorithm?
Expected behaviour
Section titled βExpected behaviourβ- If any validation check fails, display an alert message to prompt the user to enter the required information.
- The function should not continue to log the form data to the console if any of the validation checks fail.
- If all validation checks pass, the form data should be logged to the console as before.
Solution
Section titled βSolutionβ-
Validating with an object
Section titled βValidating with an objectβThere are several ways to do this, but one of the most efficient and scaleable is to use an object.
Place this object at the top of your event listener:
index.js // Capture user's input on form submissionlet form = document.querySelector("form");form.addEventListener("submit", function (event) {event.preventDefault();const maxHoursPerLevel = {basic: 5,advanced: 10,};29 collapsed lines// Store the user's email address as userEmail (string/text)let userEmail = document.querySelector("#email").value;// Store the user's level as userLevel (string/text)let userLevel = document.querySelector("#level").value;// Store the user's hours of study as userHours (number)let userHours = parseInt(document.querySelector("#hoursPerWeek").value);// Validate the user's input// Check if the user has provided an email addressif (userEmail === "") {alert("Please enter your email address.");return;}// Check if the user has selected a levelif (userLevel === "") {alert("Please select a level of study");}// Check if the user has specified at least one hour of studyif (isNaN(userHours) || userHours < 1) {alert("Please enter at least one hour of tuition.");return;}console.log({ userEmail, userLevel, userHours });});// Calculate the total cost// Display the total cost to the user -
Now, just below the check for the number of hours, add the validation code that ensures the level selected is valid, and that the number of hours requested is within the allowed range:
index.js // Capture user's input on form submissionlet form = document.querySelector("form");form.addEventListener("submit", function (event) {event.preventDefault();const maxHoursPerLevel = {basic: 5,advanced: 10,};26 collapsed lines// Store the user's email address as userEmail (string/text)let userEmail = document.querySelector("#email").value;// Store the user's level as userLevel (string/text)let userLevel = document.querySelector("#level").value;// Store the user's hours of study as userHours (number)let userHours = parseInt(document.querySelector("#hoursPerWeek").value);// Validate the user's input// Check if the user has provided an email addressif (userEmail === "") {alert("Please enter your email address.");return;}// Check if the user has selected a levelif (userLevel === "") {alert("Please select a level of study");}// Check if the user has specified at least one hour of studyif (isNaN(userHours) || userHours < 1) {alert("Please enter at least one hour of tuition.");return;}// Is userLevel valid?if (!maxHoursPerLevel.hasOwnProperty(userLevel)) {alert("Invalid level of study selected.");return;}// Is userHours within range?const maxAllowedHours = maxHoursPerLevel[userLevel];if (userHours > maxAllowedHours) {alert(`You can only study a maximum of ${maxAllowedHours} hours per week.`);return;}console.log({ userEmail, userLevel, userHours });});// Calculate the total cost// Display the total cost to the user -
This is approach is most efficient because it allows you to easily add more levels and their corresponding maximum hours without having to change the validation code.
Likewise, the
maxHoursPerLevel
object doubles as a reference for valid levels, as each key in the object corresponds to a valid level of study.
Summary
Section titled βSummaryβIn this tutorial, you learned how to validate user input in a sign-up form for Harmony Music Academy.
We have covered:
- Presence checking to ensure that the user has entered data in all required fields.
- Content validation to ensure that the data entered is of the correct type and format.
- Using a
return
statement to stop the function from executing if any validation check fails.
Next steps
Section titled βNext stepsβIn the next step, we will learn how to optimise the error messages shown to users when they fail to complete the required information.