So this time around, we want to improve our validation and we want to do a few things, actually.
So right now we have this.
It displays an error message.
It displays a nice red around it when there's a problem, and that works great.
So we want to add that same kind of logic to all of these.
We also want the form to repopulate with user entered information after an error is detected and the
pages displayed.
So we want the form to be partially filled out and show errors where errors take place.
And we also want to simplify our method of checking for required fields.
So let's get started.
So I want to go back to my code and I'm going to, first of all, go to the Make Reservation page and
I'm going to think about what how I can display information on this particular form.
So this part of the form right here, which is the first name I want this to display, whatever the
user entered, if they've entered information.
But there's an error and I'm displaying this form.
So how do I do that?
Let's go back to our handlers.
And you remember here, when I rendered the template, I actually pasted this data object.
And the data object is a map of typed string interface, which means we can look up things by string
and we can store anything we want in there.
And we stored one value in that map reservation with the value of reservation, which is this, which
is pre populated with the user's information, whatever they enter in the form.
Well, we can do a similar thing up here when we're displaying the reservation page with a get request.
So we first come to that page.
We can actually create a variable called var empty reservation that's of type models, dot reservation.
So that is an empty reservation, but it has all the necessary fields.
So then we can just create another map so we can say data is equal to make map string interface and
put a value in there.
So data reservation and it's important that it has exactly the same name that I'm using down here when
I say data reservation.
So I create that and in that I store my empty reservation and then I just pass that as data.
So now I have an empty reservation the very first time this page is displayed, which means that I can
come in here and on this input I can use an attribute we haven't paid attention to so far, and it's
called value.
So what is the value to be displayed when this form is rendered and when that's going to be equal to
my reservation?
Now, how am I going to get the reservation out of that?
Well, the simplest way to get the reservation out of my data pass to the template is to come up before
I'm going to use it, but in the same block.
So in the content block, I'm going to declare a new variable using a dollar sign.
Kind of feels like.
But it's not.
And I'll just call this race.
And that's going to be equal to I'm assigning of the value of index data, which is from my template
data.
And inside of that I have a reservation.
So I'm storing the value of my empty reservation the first time this page is displayed in a variable
called Sunrise.
So I can copy that.
Come down here and paste it right in here, put my double bass brackets around it or curly brackets
or whatever you want to call them, rez dot first name.
And I can just copy this and do it for all of the fields so I can come down here for last name and change
value to Rez last name.
Make sure there's a space there.
Do the same thing here.
And this one is for email.
So it's red dot email and again case matters because it's actually named email with a capital E in the
models, dot in the model and then phone resort.
So now if I save that and start my application and start it up, does it compile as it does?
So let's go back to our form, reload the page.
So you know, it's a new page, a blank form, and this time I'll leave first name blank because that's
the only required field I have right now.
We're going to make that better in a minute and I'll put Smith John at not some dotcom doesn't matter.
And some phone number five five five three three now.
And I submit this these should be repopulated and they are I get an error message, but these are repopulate.
So I need to fix this error, but I don't have to retype all this.
And that's great.
Now, how did that work?
Well, let's go back to our handlers.
So back to our handlers, which are right here and hide this and look at when it's rendering it the
first time.
So when our roots start right from the beginning, when I hit this page for the first time, make reservation,
I'm going to the reservation handler, which creates an empty reservation, stores it in my data variable
and passes that to the template along with.
An empty form, so all of this is basically pristine.
There is no useful data in there at all, and that's exactly what I want.
The first time the pages rendered when they post the data.
Now it's calling this handler make reservation post and it goes to post reservation.
And that one says pass the form, create a reservation variable.
That's a type models reservation and store, whatever they entered in there, whether it's good, bad
or indifferent data, if they enter nothing, it'll be empty.
If they entered the wrong information, it'll be the wrong information.
Then I create a new form, pass it through my validation, which has one rule right now that has to
have first name.
And if it's not valid, I just pass that reservation object that I created here and I pass the form
that I created here.
So because there's information in both form and data now, it displays on the form and that's all there
is to it.
So let's go back and clean a few things up.
First of all, I want this same error message to do is to be displayed for all of my fields, whatever
the error message may be.
But I can't use my first name here.
I have to use the last name, which I cannot spell right.
Same thing for email.
Might be a different error message, but I definitely if there's an error, I want it displayed.
And the same thing for phone, which is phone.
OK, and I also had this little bit that goes inside the class, so it puts that nice coloring around
the input and look at that, I misspelled label everywhere the label.
That one's right.
No big deal.
Eladio, am I to automatically fix the closing to yours.
Might not check label.
OK, inside class form control.
I could again put that logic with form errors.
Get this time its last name to change that the last name.
Nothing else changes.
And for this one with form errors get this time it's email and then for phone inside that class and
this time it's email and I should work.
So if I come back here now and reload this oh reload it this way by clicking up here in the world bar
and hit enter and try making a reservation.
Now I should get an error message for only the first one, but it should work.
But if I add the required for these three that it'll work for those as well.
Now last time I said, when you look at the handlers which are right here when we're doing the check,
I said it's really awkward to have to put one command for every single required field.
And I suggest that it might be better in our forms package to either change the hands or to add a new
function in there.
So how are we going to do that?
Well, it's actually easier than you might think.
All I want to do is create a new function and I'll put it right here func.
And again, it has to point to the form where a form pointer the receiver and I'm going to call this
when required.
And this one is going to take one name, one parameter fields, but I'm going to make it off type dot,
dot, dot, string.
And you haven't seen that yet.
It doesn't return anything.
This is called a very ADIC function and a very ADIC function says you can have as many types of string
as you want here, which means I can pass that one required field or five required fields or 50 required
fields and it will do everything I want.
And what I'm going to do in the function is range through that field variable, which might have at
least one thing in it, but it might have 10 things in it.
So I'll just go for and I don't care about the index, so I'll use the underscore to ignore it.
Field is assigned the value of.
Range fields and what do I want to do inside there?
Well, let's get the value of that.
So value is equal F, which is our form object, which we got from a receiver and that has a feel,
a function called get.
And I can get the key of the string by string, which is field in this case.
So if I have first name, last name, email, phone, as parameters passed the first time I come through
here, value which I'm going to spell.
Right.
Which I'm eventually going to spell.
Right.
Value will say go to the form object right here, this receiver call the method get, which is right
on that.
It's right in this package forms and get the field named first name.
OK, so I've got it great.
And I say really simple stuff.
If and this is a package we haven't used much, but we will be using it more.
Strings is a built in package in the Go Standard Library and I'm going to call Trem Space, Trem Space.
And all that does is dreamspace from either end of the string, end of the string is empty, will have
nothing, but it'll give me everything I need in here.
So it removes extraneous spaces that the user might have typed in by mistake, if that is equal to nothing.
In other words, if that form has no value.
And of course, I have to put the value in there what I'm trimming.
So when you trimmed the value, when you remove the extraneous spaces from the variable value which
is currently assigned to first name, if that's the first parameter pass to it, if that's equal to
nothing, then what do I want to do?
Just add an error f errors and I'll call the method add and I'm passing at the name of field, which
is what it's when we arrange through the list of fields, it'll be whatever that field currently is
and an error message.
This field cannot be like that's all I have to do and I don't have to do anything else because if this
condition is never met, this adding of an error will never fire, which means I can go back to my handlers
and don't use this this comment that out, I'll just say form required and pass in the fields.
First name, last name and I'll leave one out email Ali Fona.
OK, so I'm not passing that now.
I'm not calling the house function and I'm going to change that in a minute because it will be useful
later on.
But I'm just calling this.
If any of these have an empty string for their value, then form will have an error added to its errors.
A variable.
So let's restart this, close the application, start it back up, go back to our page and see if we
did anything wrong.
So I'll reload the page and I'll just try something different and look, they're required.
Oh, I made a mistake on the form one somehow, which is why I'm testing it this way.
Let's go back and fix that.
So I have to be on the make reservation page.
And I said on the last one I left email there when that should have been phone so I can just go back
here.
It should reload the page.
We rebuild the cache on the lower than it does not go to only three required field because I left my
phone out.
So that works really well.
But what if I feel some information in A, B, C and D?
And it gives me an error.
Let's find out what the error is.
It's got to be in somewhere in my template formed Ayers Target phone Ardizzone, that looks OK.
What I do want to do here is just start commenting things like comment on it and I reload the page and
let it repost the information.
Still got an error there.
So it's not in there.
Save that, reload the page, still have an error.
Commentator, reload the page, still have an error, and I will comment this last one at.
Oh, you know what, I'm done.
I'll be uncommented.
Let me just undo all that.
Of course, it's there's no error.
When I reload this page, it's blank because I passed validation.
So I need to fail validation in order to reload the page, which means I need to go back and uncommented
this last one.
Reload the page there where now this is required.
This is required.
This is not so.
I'll put one in here, one in there.
Leave that one empty because it's required and put one in there.
So I should get A, B and C and an arrow displayed on this.
And I do.
That works really well.
What if that's not the only validation I want?
What if I want it to fail if you don't have at least two characters or three characters in first name?
Well, we don't have a validator for that yet, so let's go write one.
It's really easy to go back to our format package reforms page and we will create a new very a new and
a validator.
And this one I'm going to go with.
I'll just write it from scratch.
I don't need to copy and paste func f pointier to form and I'll call this one min length which will
check for the minimum length of the string.
And it needs to know three things.
First of all, what's the field.
And it'll be a string.
Secondly, what's the minimum like you want.
And I'll call that length and that'll be an entry.
And thirdly, what's the request.
And that's going to be R and a pointer to a HTP request.
So I'll pass that on that and it's going to return bool, even though it doesn't have to.
We're going to do that.
OK, so how do we do this.
Well, X is assigned are not formed yet, whatever your field name is.
So that gets us a string and then we just check to see if it's long enough.
If Lenn of X is less than the length, what do I want to do at an error once again, after errors don't
add and it's for a field, so we pass in our field name and the error is this time I'm going to use
my format as print f package or function because I need to put the I need to give them a more meaningful
error message than hope your your fields not long enough.
Well how long does it have to be.
We might as well tell them so we'll say this field must be at.
Liste percent D characters long, and then we'll replace that placeholder percent D with our Ent.,
which we hold length, so we add that error and will return false, even though we're not using using
this bull at some point, this might be useful information.
Otherwise we return trip.
So if this never gets executed because the minimum length is met, that requirement that it returns
true, otherwise it returns false and stops processing because we return that function, return from
that function.
So let's give it a comment in length.
And it says checks for string, minimum length.
OK, so now I have this min length function.
Let's go use it.
So I'm going to on this page like this, be at least three characters long.
So back and find my handlers.
There they are.
And I can get rid of this comic because I'm not using it anymore.
How do I add another rule to my validation while I just call form again?
One of the methods on form, form in length, my field will be first name and the minimum length will
be three.
And it also expects my requests will pass at my request variable, which I have because I'm writing
a handler right there.
Stop the application, run the application, go back to this form, reload the page by highlighting
that you are hitting enter so it doesn't repost the form data and I'll put in a first name.
That's not long enough, eh?
And I'll put in a last name B and an email C or C C and will leave Fome empty because it's not required.
So it should give me an error on this.
But there's actually two errors being generated.
One is actually no, there's only one error being generated on this one.
So I can leave it empty right now.
So this if I do it this way, it's going to generate two errors.
The first one is this field is required and you've given me nothing.
And the second is there's actually a minimum character length requirement on this field.
Which one is it going to display?
It's going to display the one we added in first, because when we call, get on our R.
Where is it here?
It's on our errors.
I think it is when we call get we're returning indexed zero, which is the first thing in that slice.
So here when I filled this out, the first error in that slice is the field cannot be blank.
Now let's put a character in there which still is going to fail because it's not at least three characters
along this field.
Must be at least three three characters long.
And now if I fill it out, it'll submit it and we'll get a blank page.
All right.
Last thing I want to do right now is to go back to our handlers, know our forms.
And I said I was going to make a change to required.
Well, I'm not required to has, but I need a permit for required.
So I'll put a comment in here.
Checks for required fields.
OK.
And it is under has I said, well, I don't want to add an error for this one necessarily and I don't
want an added error for this one.
This will become a useful function because there are certain fields like a checkbox, for example,
that are actually handled differently than a text input.
So when you put a checkbox on a form, if the checkbox is checked, then that value, whatever the input
is named, the input type equals checkbox, if I call mine, agreed to terms and conditions that variable
agree to terms and conditions is passed as part of the post request.
But if it's not not checked, it's not even included at all.
So you can't do anything with it.
So this has will be a useful feature for us to check whether or not submitted form data includes a certain
field.
So I'm going to leave that one alone except for removing that error.
So now it's available to us and we are good to go.
The last thing we need to actually check on this make reservation form the posting, part of it at least,
is that email is really an email and we'll do that in the next package or next lecture, and we'll do
it by importing a third party package called Go Validator, which is really good.
A time tested.
It's been around for a long time and I use it every day and we'll do that in the next lecture.