With the roadmap set, we will start to implement configurable validations for our Models.
All right. Using the readme from the previous video, I've described our first tests here that are going to be failing. I'm just going to isolate this first one here.
We can see that the pieces we've defined -- we've defined a function, the way someone might define a validator for us.
This one's called min, like we've seen before, and it says that the value that's passed in, or the value of the field, has a length that is greater than or equal to this.min. The message is also going to use this.min to say that it must be greater than or equal to whatever the configured value is.
Then we're using the validator class that we've yet to define, to create a new validator using this min function. Then we're going to configure it with the minimum value of five.
This is going to be equivalent to saying post.validate. We'll say the title has a length with a min of five -- so five is the configuration that it's going to receive.
We have two tests here. We're first testing that, with this configured function, the value "hello" -- which has five letters -- validates to "true" and "hi" validates to "false" because it has less than five letters.
Then the second piece that we'll test in a bit, says that the message, once it's been configured, reads "must be greater than five."
If we save this out, we see that we have this first error, "bc validatable provider doesn't exist." That's because, way up here, we included bc validatable, and we've yet to define that. Let's go ahead and define this.
We're going to define our core file for this module. I like to do it like this -- this is going to be in our module base class. We'll yoink this name that we already defined...and there we go.
All right, now we do not have the validator provider. So let's go ahead and create a home for that.
There we go. Saving that out, now we have "Undefined is not a constructor. Evaluating new validator." Let's fix that. We're going to create a validator constructor. We know that it takes a validation function, and we're just going to return this validator here.
We'll set a couple of named properties already, so we'll say "validation function.name." In this case, the function was named "min," so we'll grab that name.
We'll say "this.message=validation function.message" as well, so the default message of the min function was another function. That's going to allow us to set a default, or someone can override that.
Finally, we want to define the "configure" function. We know that the configuration function is going to have some options set.
I want to just go ahead and set some default options, defining another function here. This, of course, also takes those options.
This is going to allow us to ensure that the options passed in are always fairly consistent, or we can read them consistently.
Let's say if not is object -- in the case that we had before, the option was just five. We might also have strings, we might also have arrays, we might have, maybe even functions -- who knows the myriad values that might be passed into validators in the future?
What we want to say is that "options" is equal to value options. So the value of this object is going to be whatever was passed in, so in this case it's going to be five.
The message is going to be this.message -- so if there was no message set, we're going to use the default message from the validation function.
Then we want to say if the name of the validation function is not undefined, then options validation function.name is going to be equal to options.value.
That's how we're going to be able to pass in something like options.min, which was the name of the function, and that's going to be assigned in this case to the value five.
Finally, we're just going to return these options. I think these are nicer options -- something like min is a little bit more readable.
Finally, from here what I want to do to solve the problems we have so far, is just to return a new validation function, which is something we're going to describe.
That's going to be something that takes a validation function, and is going to take some options. So again we're going to give it some defaults.
We'll say that the defaults are the options. Then we'll back it up with the values that are exposed on this, so if there are any additional values that weren't set -- like in this case, we had "this.message" -- but in the case where a user passed an object but they didn't pass a message, we'll continue to default to this message here.
Now we need to go ahead and create the validation function and open that up. We'll just paste in our boilerplate. Here we're going to return the validation function. It's a construction that we know takes a validation function and some options.
We'll keep this consistent, so we'll say "return validation function" and, up here, of course this is going to be a constructor, so it's the function validation function.
The only thing we need to do right now is say that the function is equal to the bound validation function and we're binding it to the option.
That's why, within the context of the message or the validation function itself, what we have is this.min instead of options.min -- something like that.
Here, we're just going to return the function and I'm just going to copy this guy out and paste him in...clean this up a little bit -- we already have that there -- and success, we have our first test passing.
If we return back here and evaluate that, we've properly configured this.
What we haven't configured yet is the message, "Must be greater than five," so we have that failing. Right now, the message is undefined.
The reason for that is, if we head back to the validation function, because what we actually returned was the validation function, so we want to say "function.message=" and I'm going to say here, "configure message," and again, that's just going to perform some work for us.
If someone passes in a string option -- we'll say if options.message is a string -- then we just want to return options.message. But if it is a function, we want to return options.message.apply to the options. That way, it gets passed in, the options as the context, as well.
Now all of our tests are passing.
Congratulations, guys. We have successfully implemented the first part of the validator library.