Day 18: Forms
Lesson 2: Form Validation
Click the Add button with the form empty. See how we add an entry to our list that looks like this : $ x
? That's dumb right?
Well let's use some HTML to make our values required.
Change your form to look like this.
1<form id="stock-form"> 2 <label for="name">Broom Name</label> 3 <input type="text" name="name" required /> 4 <label for="price">Price</label> 5 <input type="number" name="price" required /> 6 <label for="quantity">Quantity</label> 7 <input type="number" name="quantity" required /> 8 <button type="submit">Add</button> 9</form>
Now click Add and you'll see we get a note to tell us that the fields are required. And we didn't need to write any JavaScript at all!
What if we want a more complicated validation? Let's say we know that our shop only stocks a certain range of brooms, let's say the Comet and the Nimbus ranges and we don't want to accept any other types.
Firstly change your Add button to this.
1<button type="submit" id="form-submit" disabled>Add</button>
And then add this to the end of your JavaScript section.
1const handleOnInput = (e) => { 2 const formData = new FormData(e.currentTarget); 3 const formProps = Object.fromEntries(formData); 4 5 let nameValid = false; 6 7 if ( 8 formProps.name.toLowerCase().includes("nimbus") || 9 formProps.name.toLowerCase().includes("comet") 10 ) { 11 nameValid = true; 12 } 13 14 const priceValid = !isNaN(parseInt(formProps.price)); 15 const quantityValid = !isNaN(parseInt(formProps.quantity)); 16 17 if (nameValid && priceValid && quantityValid) { 18 document.getElementById("form-submit").disabled = false; 19 } else { 20 document.getElementById("form-submit").disabled = true; 21 } 22}; 23 24form.oninput = handleOnInput;
There's lot going on here so let's break it down.
We create an function called handleOnInput
that we attach to the form
's oninput
event handler. The oninput
event fires every time there is input into the form, so every key press on the form will fire this event handler.
In handleOnInput
we get the form fields as a nice object. We have to change the target
as while the event handler is on the form, the element actually first firing the event is the input field that changed. So, where as with onsubmit
we could just use e.target
to get the reference to the <form>
we now need to use e.currentTarget
to get it instead.
1const formData = new FormData(e.currentTarget); 2const formProps = Object.fromEntries(formData);
We then create a variable to determine if the name
is valid, we start with it being false
.
We then check to see if name
includes the substring nimbus
or comet
. We make the string from the user lowercase first so it's easier to compare. If comet or nimbus appear in the name string then we assume it's valid and set nameValid = true
.
1if ( 2 formProps.name.toLowerCase().includes("nimbus") || 3 formProps.name.toLowerCase().includes("comet") 4) { 5 nameValid = true; 6}
Next up we need to check if the number fields have valid numbers. This is trickier that you would expect as we will have been given them as strings and not numbers. So we need to use the function parseInt()
to see if there is a valid number in the string. If there isn't then we will get sent back NaN
, which literally stands for Not a Number
.
Which sounds handy but it's not because NaN
's origins are routed in complicated floating point math and so the best thing to do is use the function isNaN
to determine if we have a valid number or NaN
.
We land up with.
1const priceValid = !isNaN(parseInt(formProps.price)); 2const quantityValid = !isNaN(parseInt(formProps.quantity));
To check if price
and quantity
are numbers.
How is NaN
weird you might ask? Well I won't go into great detail but I will leave you with the note that NaN
isn't equal to itself.
That's right, where 1 == 1
and 'a' === 'a'
will be be true, NaN === NaN
will be false.
Then finally we check if all fields are valid, if they are we set the button's disabled to false and if they aren't then we set it to true.
The reason we actually include the else side of this is that if we didn't, someone could make valid entries and then go back, edit a field and the button would still be enabled.