Instructor: We came up with this definition of an API object which defines how our form should be created dynamically. What we see here is basically a person, where we have the different kind of properties and then we have some metadata, which is the label of the form, actual value of the property, and the kind of field we would like to render in our HTML code.
We then pass this into our dynamic form component, and inside there, we dynamically generate a form by using the reactive forms pattern. You can see that for down here, where we basically iterate over that form data object, and then dynamically instantiate some form controls.
Our next step, as in every proper form, is to add some validation. Whenever the user doesn't enter some value where it is actually required, we would like to show some notification to the user.
Normally, such validators are basically attached here as the second parameter into our form control, so we could do something like validators.required for making our first name required. In our case, we would like, of course, to enter this information dynamically such as we did with all other values, as well.
Let's jump back to our app component, and let's define here how our metadata would look like for defining such validators.
What we do here is we define a validator's object such that we can specify then as the key of the objects, or the property name, the name of the validator which we would like to attach, and then the actual value of the validator, like in the require validator is simply true, but it could be also some other value.
Let's start with this simple example. We would now go back to our dynamic form component, and then inside here, we get a series of validators. Therefore, we would have to create some method. Let's call it map validator.
Let's pass in the actual validators, which is under the prop property, so the current property we are processing for our data object.validators, which is the property we just defined. Here, we can now start processing it. If the validators are actually defined, we do something with it.
Otherwise, we simply return an empty array, so nothing will happen. Then inside here we have to do some mapping. This is an object, and it is exactly the object which we defined here, so it would be this one. Therefore, we have to iterate over, and let's use the object.keys, as we have already seen, validators, and we need to map them to a proper validator, which is built in into Angular.
Here, we would get the validation type, let's call it. Then we can say if the validation type is equals required, then we simply return validators.required. We can also add immediately another one. Let's say if validation type equals min, then return validators.min.
The min validator also takes a value, which we can define then later on our API object. That value would then be stored directly in that validators array under the property which are currently processing, which is the validation type. We also need to adjust here our syntactic error.
We have the mapping established. Now if we refresh the form and we remove here the name, we actually cannot see any error yet.
The problem is not that our validator doesn't work. The problem is that we don't display any kind of error message whenever it fails. Therefore, directly after that diff where we render all our input controls, we add another one, which will be the container for our validation error messages. Let's add here also class error, and also some very simple styling.
We would like to activate this diff here whenever some validation fails on our current control which we are processing. We can get that form control by using the form.getprop.key, which will actually represent basically the first name control, the age control, the gender control, and so on. Whenever that is invalid, this diff will be shown.
For better user friendliness, we should also add here some more clauses, like to activate this also only when the form, so the prop.key, has been interacted with, or it has been touched by the user. What's missing now is to display the single type of errors for the required validator and the min validator, etc.
Let's create here a diff, or also a span would be fine perfectly, and we again need to get the actual control which we are processing, which has an errors property. Inside there, we say whenever the required validator failed, so that required property would be populated, then you print out the message, "You have to provide a value."
Similarly for the min validators, so let's copy this over here, just that we need to require, obviously, the name of the validator. Here we can say the message, "You have to provide a value greater or equal to..."
Here we can access a property of that min validator. That one doesn't have only true or false, but it has a value, which indicates the actual specified minimal required value to enter. Now let's try. When we remove now the name, you can see that the validator shows up properly.
We didn't add a min validator yet, so we can go now and dynamically specify one, like for the age validators, and we say min. You have to be at least an adult, so older than 18 years old. Now if we go here and we decrease that number input, when we go below 18, you can see how the error message gets correctly rendered on our form.
Of course, you would have to add further validators, like you have to add further mappings for all the other validators which are present. Also down here, you have to specify those mappings to map them to proper validators accordingly.