Did you give it a go?
I hope so.
But don't worry if you couldn't quite figure it out.
It is a bit tricky and there is a very tricky nuance when working with the Constraint Validation API.
So I'm going to show you how we resolve it. Before we do,
here's our HTML.
We've got a label which is just asking for the username and of course we've got our input type of text.
We've got our required attribute on there and there is the pattern -
the regex that we spoke about in the introduction video.
Very, very simple.
And if we go to the browser, this is what it looks like.
But right now the user can, or obviously the user will be prevented from submitting the form.
We've got a default error message which we want to change and the user can just type anything.
Oh, of course it has to match the regex, smaller case uppercase, then the user can submit.
But we want our own custom error messages.
How does that work?
Well, as you know, we have to wrap everything in ....
that's right,
script tags.
The first thing we want to do is we want to access this Constraint Validation API.
In order to do that, we have to work with some interface.
The one we're going to work with here is this input element.
So let's grab it.
Let's define a variable called nameInput and we can access our document, querySelector(), and we
want to query select our input element.
It really, really is that simple.
That's the first step. (sound effect: mission completed)
Now, what I want to do is I want to access this variable, aka the element of input, and we want to
add our own event listener. And I gave you a clue, didn't I?
I want to listen for the invalid event. And the invalid event is going to be fired every time the value
of the input does not meet that pattern
regex,
right.
Also, we're going to get this invalid event when the required value is specified, but of course there
is no value associated with that input.
So when this event is fired, what do we want to happen?
Well, we want to execute our callback function.
Well, let's tackle the first issue.
And the first issue is if nothing is entered into that input box.
Well, in that case, we know that our name input is going to have a value and that value is going to
be an empty string.
Right?
There's going to be nothing.
And if that occurs, if this is true, then we want to define our own custom error message.
We already know how to do this.
We can access our element, and now we're using the Constraint Validation API because we can access the
setCustomValidity() message directly.
We can just say "Silly billy, you have not typed anything."
Right, and we can save this.
Let's go to the browser and test it. Go to the browser.
Try and submit.
And there we go.
We've got our own custom error message.
But you'll notice if now the user types characters and tries to submit, we keep getting this error
message.
Because remember I said once we use the setCustomValidity() method, we're telling the browser that
that element is invalid regardless of whether it's actually not invalid anymore.
And that's the slight nuance that I was telling you about earlier.
But anyway, we're going to solve that shortly.
We've dealt with the first issue where we get an invalid event and the name input does not have a value.
So we've dealt with that scenario.
Now we're going to deal with the next scenario.
So when we reach this ELSE block, we know that, (a) we've got an invalid event and (b), we know the
user has typed some characters.
So again, let's set our own custom error message here,
setCustomValidity() method, and here we can say "Usernames need to contain at least one uppercase
and one lowercase
letter.
Try again."
So let's save this.
All right.
Let's go to the browser and test this.
Right.
If the user starts typing, clicks submit, we get our own custom error message.
Very, very cool.
But you'll notice now we have a problem because if the user then types a capital letter, so we've got
one uppercase, one lowercase,
if the user submits, we're going to be in this perpetual state where we are always having an error.
Remember, it's because we've used the setCustomValidity() method which tells the browser that this
input box is always going to be invalid.
How do we stop it?
Well, remember, we have to set the custom validity message to an empty string, and when it's an empty
string it will be valid.
Remember that.
But we can't set it ...
if we look at our code, we can't set the setCustomValidity message to an empty string here because
this is when we're dealing with an invalid error.
So what we have to actually do, and this is the slight nuance I was telling you about, right,
we have to access our nameInput, add another event listener and this event listener is just going
to be listening for the input event,
right.
So every time a character is typed, I want to listen for this event and we want to access our
nameInput.
And this time I want to set the custom validity to an empty string.
Right.
That's all I want to do.
And to prove that this works, let's go to the browser.
If the user types
nothing, gets an error
message. Starts typing,
uh, let's do a capital "D", tries to submit,
now we are allowed to do so. If the user just types lowercase and clicks submit
we get a custom error message.
But did you notice there's a problem, my dear students.
Did you notice it?
It was very, very slight.
But you may have picked it up.
We know the first step works.
"Silly billy, you've not typed anything."
But if now the user types the character
"a", look at that.
We're getting the error message displayed by the browser.
We're not getting our custom error message.
In fact, we only going to get our custom error message when the user hits submit because only when
submit is issued,
is this invalid error message emitted, and only then do our custom error messages apply.
We don't want that to happen.
So every time a character is pressed, right,
in other words, every time an input event is fired, we want to fire off another method on our constraint
validation API.
We want to execute the checkValidity() method because if that is false, the invalid event is going to
be fired and our code will execute.
So if we do that on every single iteration, that should solve our problem.
So let's refresh the browser.
Okay.
We can submit - "Silly billy, you have not typed anything". But if now the user types the character "a" boom, how
awesome is that?
We get our own custom error message. And of course it's going to happen until you know we can hit submit
again.
It's going to happen until we have a capital letter.
There we go.
And if we now submit, we are allowed to do so.
The user can just do a capital D.
Let's just do capitals submit.
It's not working.
But as soon as the user then goes to lowercase.
We can now submit.
I know, I know this can be quite confusing, but let's just jump to the code.
It really is quite intuitive once you understand what's going on.
If we use the setCustomValidity() method and we write our own custom message, we are basically in a perpetual
state of an error - we're telling the browser the input is in an invalid state and our custom error
message should be shown.
That's why we couldn't just rely on our one block of code here
by listening for the invalid event. We had to create another type of event we listen for, and that
is every time the user types a character.
So let's start there.
We know that we do two things when that input event is fired.
Let me say it another way.
Every time the user types a character, we do two things.
One, we start off by saying, Hey, let's set the custom validity method's value to an empty string.
In other words, let's start off by saying that we are in a valid state.
I know it sounds strange, but hear me out.
The next thing we do is we fire off this checkValidity() method.
And remember in the lecture we discussed this.
If everything is fine on that input, true gets returned and nothing else happens.
So therefore the browser will submit the form.
But.
If there is an error, then we know that this checkValidity() method is going to fire an invalid event.
And in that case, our next block of entire code will capture the entire process.
And that's why it either shows the error message to the user,
"Silly billy, you've not typed anything" when it's an empty string.
Alternatively, in the ELSE statement if the user has typed characters but we're still getting this
invalid error, we've got another message.
"Usernames need to contain at least one uppercase and one lowercase letter.
Try again." And then we start again.
So say the user types a lowercase and an uppercase.
In that case, when that user types that uppercase, this first block of code is going to apply because
it's an input event, we're going to set it to valid and then the checkValidity() method is going to
return
true.
And that's why we are allowed to submit the form.
I know it can be quite complex, but really go through it again, go through this lecture a few times,
make sure you understand it.
It really will help you down the track.
And once you get it, it really, really is intuitive.
So anyway, I hope you had a lot of fun in this lecture.
I know I did.
But let's continue.
See you in the next lecture.