Lessons: 67Length: 8.9 hours

Next lesson playing in 5 seconds

Cancel
  • Overview
  • Transcript

5.7 Creating Custom Validators for Template-Driven Forms

In this lesson I'll show you how to create both a directive and a validator that we can use to provide custom validation to a template-driven form.

1.Introduction
6 lessons, 42:00

1.1
Introduction
00:48

1.2
Get Started With Angular-CLI
11:09

1.3
Developing With Angular-CLI
13:17

1.4
TypeScript vs. JavaScript
06:54

1.5
Angular Modules From the CLI
04:31

1.6
CLI Options
05:21

2.Get Started With Angular
7 lessons, 42:38

2.1
Bootstrapping the Application
04:30

2.2
The Application Module
04:15

2.3
The Application Component
08:06

2.4
Component Styling
03:06

2.5
Global Styling
05:11

2.6
Creating a Component With the CLI
09:34

2.7
Creating a Service With the CLI
07:56

3.Core Concepts
7 lessons, 55:20

3.1
Component Trees
06:20

3.2
Dependency Injection
06:52

3.3
Content Projection
05:38

3.4
Component and Directive Lifecycle Methods
06:31

3.5
Component-Only Lifecycle Methods
05:28

3.6
Decorators
07:36

3.7
Models
16:55

4.Template Deep Dive
11 lessons, 1:10:56

4.1
Basic Data Binding With Interpolation
05:35

4.2
Property Bindings
07:07

4.3
Attribute Bindings
03:29

4.4
Event Bindings
08:16

4.5
Class and Style Bindings
05:44

4.6
The `NgClass` and `NgStyle` Directives
05:04

4.7
The `*ngIf` Directive
04:41

4.8
The `*ngFor` Directive
09:29

4.9
Inputs
05:33

4.10
Using Pipes in a Template
07:31

4.11
Using Pipes in a Class
08:27

5.Forms
10 lessons, 1:45:41

5.1
Handling User Input With Template Reference Variables
07:06

5.2
Template-Driven Forms
11:10

5.3
Template-Driven Forms: Validation and Submission
14:00

5.4
Reactive Forms
11:26

5.5
Using a `FormBuilder`
08:01

5.6
Reactive Validation With Built-in Validators
14:53

5.7
Creating Custom Validators for Template-Driven Forms
12:18

5.8
Creating Custom Validators for Reactive Forms
08:26

5.9
Observing Form State Changes
12:40

5.10
Working With the `@HostListener` Decorator
05:41

6.Routing
9 lessons, 1:15:10

6.1
Defining and Configuring Routes
07:53

6.2
Rendering Components With Router Outlets
10:14

6.3
Using Router Links for Navigation
05:25

6.4
Navigating Routes Using the Router
06:24

6.5
Determining the Active Route Using an Activated Route
07:16

6.6
Working With Route Parameters
10:42

6.7
Using Route Guards
07:36

6.8
Observing Router Events
10:55

6.9
Adding Child Routes
08:45

7.Using the HTTP Client
5 lessons, 56:24

7.1
Sending an HTTP Request
10:52

7.2
Handling an HTTP Response
11:22

7.3
Setting Request Headers
12:33

7.4
Intercepting Requests
09:04

7.5
Finishing the Example Application
12:33

8.Testing
10 lessons, 1:23:27

8.1
Service Unit Test Preparation
10:45

8.2
Unit Testing Services
13:24

8.3
Component Unit Test Preparation
12:35

8.4
Unit Testing Components
07:27

8.5
Unit Testing Component Templates
06:58

8.6
Unit Testing Pipes
04:41

8.7
Unit Testing Directives
04:56

8.8
Unit Testing Validators
04:48

8.9
Unit Testing Observables
11:37

8.10
Unit Testing HTTP Interceptors
06:16

9.Building for Production
1 lesson, 03:40

9.1
Building for Production
03:40

10.Conclusion
1 lesson, 01:32

10.1
Conclusion
01:32


5.7 Creating Custom Validators for Template-Driven Forms

Hi, folks. In this lesson, we're gonna see how we can create custom validators and use them with template-driven forms. We can also use custom validators for reactive forms but the process is slightly different. So we'll come back and look at that in a different lesson. So this is another area in which reactive forms may be considered superior. Creating and using custom validators is actually easier when working with reactive forms. So Angular has built-in validators for any of the HTML5 validation attributes, but what if our validation is more complex and is not covered by the built-in ones? In this case, we'll need to write our own custom validator. Thankfully, Angular makes this as easy as possible for us. For template-driven forms, we actually need to create two things. We need the custom validator itself, but we also need some way to attach this validator to an element. This is what a directive is for. It allows us to define a custom attribute that we can apply to HTML elements. And that's exactly what we need. Our start component has the form where the player can enter their name. But one name we don't want them to add is dealer, because there already is a player called dealer by default in every game and having two dealer players would be weird. Our validator will make sure the player doesn't try to call themselves dealer. So first of all let's create a new directive. We can use the CLI for this. But to avoid it creating a folder with the wrong name, let's just create the folder manually ourselves first. Directives are super generic and we should be able to use them in lots of different places all over the application. And that's why I've chosen to create an _directives folder to keep our directive in because it's completely generic. So now let's use the CLI to generate our new directive. So the CLI has generated the directive and the spec file, and it's also updated the module. But I've just noticed that I've spelled the name dealer incorrectly, so I'll have to go and fix that quickly. So Angular did manage to put the new directive in the correct folder even though we used an underscore, so let's just fix the name quickly. And there's one more place that we need to fix it and that's in the app module. Perfect. So we now have the skeleton file for the directive. And let's just see what we get out of the box. So we import the directive decorator from the Angular core module. The decorator is used to specify the selector. So that is what we will actually be adding to an element to apply this directive to it. And the selector, again, just like component selectors, starts with app and that's pretty much what we get. We get the class and we get an empty constructor and that's it. So directives and components are actually very, very, similar. In fact, components are a type of directive. They're just a specialized directive that have a template and a style sheet. Directives don't have a template, so the meta objects we passed to the directive decorator doesn't support a template property. So as we're building a validator, there's some other stuff that we need to import as well. So we've brought in the abstract control class, NG_VALIDATORS, which is a collection of validators. And I did want to bring something in called Validator, but I've spelled it incorrectly. And Validator is actually an interface. And we want our directive to implement that interface So we should now get some intellisense to tell us that the class is not implementing the Validator interface correctly. And in order to implement this Validator interface correctly, our class must expose a method called validate. So we won't need a constructor, let's get rid of that. But let's add a validate method. The underlining is still there at this point, because the method's signature isn't quite right yet. All validators are passed the control being validated automatically by Angular when it checks the validity of the control. So our validate method should be passed this also. So we can add an argument called control, and we specify that it will be of the type AbstractControl. We should also provide the return type for the method. For it to be like other validators, it should return an object with the name of the error and some value, which could be a simple message or it could be a Boolean. So we're saying here that the method will return an object and that object will have strings as keys, and the value will be of the type any. So now the red underlining under the class name should go away because we're implementing the validator correctly. But we do still have this underlining under the return type because the method isn't returning anything. So what we need to do inside the validate function is check that the value of the control, which will be the name control, doesn't equal dealer. So if the control has a value, and the value of the control is equal to the string dealer, then we return this error object with the name of the error as the key and in this case just the string message that the name is not valid. We can also put the name to lowercase when we test it because it's easier than checking for different casing versions of the name. So if the control does have a value, and the value does not equal dealer, we can just return null. And that will mean that the value of the control is valid. So that's all the validation logic that we need. But we need to update the directive part of it if we want Angular to use it like it uses other validators. We need to add a providers key to the decorator meta object. So the value of this is an array, just like it is in the NG module decorator. So we pass an object to the providers array. And that object has three keys, provide, useExisting and multi. So what we're saying in this expression basically is wherever NG_VALIDATORS is provided it should use this directive as well. And we set multi to true, because there will be multiple validators inside NG_VALIDATORS. So this is why we imported NG_VALIDATORS, just to use here. Okay, great. So we should be able to make use of our custom validation directive now. We can add the attribute for the directive to the input for the player's name in the start component template. We just add it after the required attribute. And it doesn't need any special value, just the directive name is fine. So now, let's test it out So if we try to add the name dealer, we should see some kind of error styling. So it says the name is required, but essentially that validation directive is working. So as soon as we change from dealer to something else, the error styling goes away. So let's just fix the message part. I say just, it's actually a bit of a pain because we can't use any of the nice convenience methods like get or has error that we can when we're using a reactive form. So that means we're gonna have to check everything ourselves manually. So we're gonna need to change the first one as well. So first we need to check that the playerForm controls object has a control inside it called name. Then we need to check that this name control has an errors object. And then we need to check whether the errors object contains the key, required. And we also want to make sure the form itself has been touched. So now let's add the error message for if they try to use the name dealer. So that's a lot of checking that we're doing here. In this second one, remember that the name that gets added to the errors objects will be nameNotDealer. And we can at least get the message that the validator passes back. And we'll display that instead of hard-coding a generic error. So let's go back to the browser now. And let's try to add the name dealer. And it tells us that we cannot use that name, perfect. And now if we get rid of the name altogether, then we'll see the other error that the name is required. So in this lesson we saw a how to create a custom validator that can be used with template-driven forms. And because it's used with template-driven forms, we saw that we had to define the validator as a directive and we need to apply it in the template. So actually we saw how to create both a directive and a validator in this lesson. We saw that to create a validating directive we need to make sure it is provided in NG_VALIDATORS and that it should be a multi-provider. We saw that to create a validator we should implement the Validator interface, which means adding a validate method to the class, which accepts a form control and then does something with the value of that control. In this case, we just checked that the value was not equal to the string dealer. Thanks for watching.

Back to the top