{"id":740,"date":"2018-01-16T01:00:00","date_gmt":"2018-01-16T01:00:00","guid":{"rendered":"https:\/\/staging.infragistics.com\/blogs\/?p=740"},"modified":"2025-02-18T14:00:40","modified_gmt":"2025-02-18T14:00:40","slug":"custom-validators-angular-reactive-forms","status":"publish","type":"post","link":"https:\/\/www.infragistics.com\/blogs\/custom-validators-angular-reactive-forms","title":{"rendered":"How to create Custom Validators for Angular Reactive Forms"},"content":{"rendered":"\n<p>In this blog post, we will learn to create custom validators in Angular Reactive Forms. If you are new to reactive forms, learn how to <a href=\"\/blogs\/how-to-create-your-first-angular-reactive-form\/\">create your first Angular reactive form<\/a> here.<\/p>\n\n\n\n<p>Let\u2019s say we have a login form as shown in the listing below. Currently, the form controls do not have any validations attached to it.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ngOnInit() {\n    this.loginForm = new FormGroup({\n        email: new FormControl(null),\n        password: new FormControl(null),\n        age: new FormControl(null)\n    });\n}<\/pre>\n\n\n\n<p>Here, we are using FormGroup to create a reactive form. On the component template, you can attach loginForm as shown in the code listing below. Using property binding, the formGroup property of the HTML form element is set to loginForm and the formControlName value of these controls are set to the individual FormControl property of FormGroup.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;form (ngSubmit)='loginUser()' [formGroup]='loginForm' novalidate class=\"form\">\n     &lt;input formControlName='email' type=\"text\" class=\"form-control\" placeholder=\"Enter Email\" \/>\n     &lt;br \/>\n     &lt;input formControlName='password' type=\"password\" class=\"form-control\" placeholder=\"Enter Password\" \/>\n     &lt;br \/>\n     &lt;input formControlName='age' type=\"number\" class=\"form-control\" placeholder=\"Enter Age\" \/>\n     &lt;br \/>\n     &lt;button [disabled]='loginForm.invalid' class=\"btn btn-default\">Login&lt;\/button>\n &lt;\/form><\/pre>\n\n\n\n<p>This will give you a reactive form in your application:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/static.infragistics.com\/marketing\/Blogs\/Migration\/00\/00\/00\/09\/43\/6153.img1.png\" alt=\" This will give you a reactive form in your application\" title=\"This will give you a reactive form in your application\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"using-validators\">Using Validators<\/h2>\n\n\n\n<p>Angular provides us many useful validators, including <strong>required<\/strong>, <strong>minLength<\/strong>, <strong>maxLength<\/strong>, and <strong>pattern<\/strong>.&nbsp; These validators are part of the <strong>Validators<\/strong> class, which comes with the <strong>@angular\/forms<\/strong> package.&nbsp;<\/p>\n\n\n\n<p>Let\u2019s assume you want to add a required validation to the email control and a maxLength validation to the password control. Here\u2019s how you do that:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ngOnInit() {\n    this.loginForm = new FormGroup({\n        email: new FormControl(null, [Validators.required]),\n        password: new FormControl(null, [Validators.required, Validators.maxLength(8)]),\n        age: new FormControl(null)\n    });\n}<\/pre>\n\n\n\n<p>To work with Validators, make sure to import them in the component class:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import\u00a0{\u00a0FormGroup,\u00a0FormControl,\u00a0Validators\u00a0}\u00a0from\u00a0'@angular\/forms';<\/pre>\n\n\n\n<p>On the template, you can use validators to show or hide an error message. Essentially, you are reading the formControl using the get() method and checking whether it has an error or not using the hasError() method. You are also checking whether the formControl is touched or not using the touched property.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;input formControlName='email' type=\"text\" class=\"form-control\" placeholder=\"Enter Email\" \/>\n&lt;div class=\"alert  alert-danger\" *ngIf=\"loginForm.get('email').hasError('required') &amp;&amp; loginForm.get('email').touched\">\n    Email is required\n&lt;\/div><\/pre>\n\n\n\n<p>If the user does not enter an email, then the reactive form will show an error as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/static.infragistics.com\/marketing\/Blogs\/Migration\/00\/00\/00\/09\/43\/6153.img2.png\" alt=\" If the user does not enter an email, then the reactive form will show an error\" title=\"If the user does not enter an email, then the reactive form will show an error\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"custom-validators\"><strong>Custom Validators<\/strong><\/h2>\n\n\n\n<p>Let us say you want the age range to be from 18 to 45. Angular does not provide us range validation; therefore, we will have to write a custom validator for this.<\/p>\n\n\n\n<p>In Angular, creating a custom validator is as simple as creating another function. The only thing you need to keep in mind is that it takes one input parameter of type AbstractControl and it returns an object of key value pair if the validation fails.<\/p>\n\n\n\n<p>Let\u2019s create a custom validator called <strong>ageRangeValidator<\/strong>, where the user should able to enter an age only if it\u2019s in a given range.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/static.infragistics.com\/marketing\/Blogs\/Migration\/00\/00\/00\/09\/43\/4405.img3.png\" alt=\"Create a custom validator called ageRangeValidator\" title=\"Create a custom validator called ageRangeValidator\"\/><\/figure>\n\n\n\n<p>The type of the first parameter is AbstractControl because it is a base class of FormControl, FormArray, and FormGroup, and it allows you to read the value of the control passed to the custom validator function. The custom validator returns either of the following:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>If the validation fails, it returns an object, which contains a key value pair. <strong>Key<\/strong> is the name of the error and the value is always <strong>Boolean<\/strong> <strong>true<\/strong>.<\/li>\n\n\n\n<li>If the validation does not fail, it returns <strong>null<\/strong>.<\/li>\n<\/ol>\n\n\n\n<p>Now, we can implement the <strong>ageRangeValidator<\/strong> custom validator in the below listing:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">function ageRangeValidator(control: AbstractControl): { [key: string]: boolean } | null {\n \n    if (control.value !== undefined &amp;&amp; (isNaN(control.value) || control.value &lt; 18 || control.value > 45)) {\n        return { 'ageRange': true };\n    }\n    return null;\n}<\/pre>\n\n\n\n<p>Here, we are hardcoding the maximum and minimum range in the validator. In the next section, we will see how to pass these parameters.<\/p>\n\n\n\n<p>Now, you can use <strong>ageRangeValidator<\/strong> with the age control as shown in the listing below. As you see, you need to add the name of the custom validator function in the array:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ngOnInit() {\n    this.loginForm = new FormGroup({\n        email: new FormControl(null, [Validators.required]),\n        password: new FormControl(null, [Validators.required, Validators.maxLength(8)]),\n        age: new FormControl(null, [ageRangeValidator])\n    });\n}<\/pre>\n\n\n\n<p>On the template, the custom validator can be used like any other validator. We are using the <strong>ageRange<\/strong> validation to show or hide the error message.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;input formControlName='age' type=\"number\" class=\"form-control\" placeholder=\"Enter Age\" \/>\n &lt;div class=\"alert  alert-danger\" *ngIf=\"loginForm.get('age').dirty &amp;&amp; loginForm.get('age').errors &amp;&amp; loginForm.get('age').errors.ageRange \">\n     Age should be in between 18 to 45 years\n &lt;\/div><\/pre>\n\n\n\n<p>If the user does not enter an age between 18 to 45, then the reactive form will show an error:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/static.infragistics.com\/marketing\/Blogs\/Migration\/00\/00\/00\/09\/43\/4405.img4.png\" alt=\" \"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>&nbsp;Now, age control is working with the custom validator. The only problem with ageRangeValidator is that hardcoded age range that only validates numbers between 18 and. To avoid a fixed range, we need to pass the maximum and minimum age to ageRangeValidator.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"passing-parameters-to-a-custom-validator\">Passing parameters to a Custom Validator<\/h2>\n\n\n\n<p>An Angular custom validator does not directly take extra input parameters aside from the reference of the control. To pass extra parameters, you need to add a custom validator inside a factory function. The factory function will then return a custom validator.<\/p>\n\n\n\n<p><strong>You heard right: in JavaScript, a function <em>can<\/em> return another function. <\/strong><\/p>\n\n\n\n<p>Essentially, to pass parameters to a custom validator you need to follow these steps:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Create a factory function and pass parameters that will be passed to the custom validator to this function.<\/li>\n\n\n\n<li>The return type of the factory function should be <strong>ValidatorFn<\/strong> which is part of <strong>@angular\/forms<\/strong><\/li>\n\n\n\n<li>Return the custom validator from the factory function.<\/li>\n<\/ol>\n\n\n\n<p>The factory function syntax will be as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/static.infragistics.com\/marketing\/Blogs\/Migration\/00\/00\/00\/09\/43\/7120.img5.png\" alt=\" \"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Now you can refactor the ageRangeValidator to accept input parameters as shown in the listing below:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">function ageRangeValidator(min: number, max: number): ValidatorFn {\n    return (control: AbstractControl): { [key: string]: boolean } | null => {\n        if (control.value !== undefined &amp;&amp; (isNaN(control.value) || control.value &lt; min || control.value > max)) {\n            return { 'ageRange': true };\n        }\n        return null;\n    };\n}<\/pre>\n\n\n\n<p>We are using the input parameters <strong>max<\/strong> and <strong>min<\/strong> to validate age control. Now, you can use ageRangeValidator with age control and pass the values for max and min as shown in the listing below:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">min = 10;\nmax = 20;\nngOnInit() {\n    this.loginForm = new FormGroup({\n        email: new FormControl(null, [Validators.required]),\n        password: new FormControl(null, [Validators.required, Validators.maxLength(8)]),\n        age: new FormControl(null, [ageRangeValidator(this.min, this.max)])\n    });\n}<\/pre>\n\n\n\n<p>On the template, the custom validator can be used like any other validator. We are using ageRange validation to show or hide an error message:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;input formControlName='age' type=\"number\" class=\"form-control\" placeholder=\"Enter Age\" \/>\n  &lt;div class=\"alert  alert-danger\" *ngIf=\"loginForm.get('age').dirty &amp;&amp; loginForm.get('age').errors &amp;&amp; loginForm.get('age').errors.ageRange \">\n      Age should be in between {{min}} to {{max}} years\n  &lt;\/div><\/pre>\n\n\n\n<p>In this case, if the user does not enter an age between 10 and 20, the error message will be shown as seen below:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/static.infragistics.com\/marketing\/Blogs\/Migration\/00\/00\/00\/09\/43\/7120.img6.png\" alt=\" In this case, if the user does not enter an age between 10 and 20, the error message will be shown\" title=\"In this case, if the user does not enter an age between 10 and 20, the error message will be shown\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>And there you have it: how to create a custom validator for Angular Reactive Forms.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><b>Like this post?<\/b><\/h4>\n\n\n\n<p>If you like this post, please share it. In addition, if you haven\u2019t checked out our <a href=\"\/products\/ignite-ui-angular\">Angular Components<\/a>,&nbsp;be sure to do so!<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"\/products\/ignite-ui-angular\/download\"><img decoding=\"async\" src=\"https:\/\/static.infragistics.com\/marketing\/Blog-in-content-ads\/Ignite-UI-Angular\/ignite-ui-angular-you-get-ad.gif\" alt=\"Ignite UI for Angular\"\/><\/a><\/figure>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this blog post, we will learn to create custom validators in Angular Reactive Forms. If you are new to reactive forms, learn how to create your first Angular reactive form here.<\/p>\n","protected":false},"author":65,"featured_media":1166,"comment_status":"publish","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[],"class_list":["post-740","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-angular"],"_links":{"self":[{"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/posts\/740","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/users\/65"}],"replies":[{"embeddable":true,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/comments?post=740"}],"version-history":[{"count":8,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/posts\/740\/revisions"}],"predecessor-version":[{"id":1880,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/posts\/740\/revisions\/1880"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/media\/1166"}],"wp:attachment":[{"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/media?parent=740"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/categories?post=740"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/tags?post=740"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}