Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Parametrized Validators in Dynamic Forms
Mynd.co profile imageMateo Tibaquirá
Mateo Tibaquirá forMynd.co

Posted on • Edited on

     

Parametrized Validators in Dynamic Forms

TL;DR
We are building the documentation of@myndpm/dyn-forms atmynd.dev and we've added support for a variety of custom functions like Validators, AsyncValidators, Matchers, Conditions and more.

The next crucial part of any form is validation, akaValidators andAsyncValidators, and we took some time to study a nice way to implement them and we picked the most declarative one:

createMatConfig('INPUT',{name:'quantity',validators:['required',['min',1]],asyncValidators:['myAsyncValidator'],
Enter fullscreen modeExit fullscreen mode

Angular Validators

Angular provides defaultValidators that we're used to consume programatically in our Reactive Forms, some of them are Validator Functions (ValidatorFn) likeValidators.required, and some others are Validator Factories ((args) => ValidatorFn) which builds a Validator based on a required parameter likeValidators.minLength(4).

The definition of a Validator Function is:

(control:AbstractControl)=>ValidationErrors|null
Enter fullscreen modeExit fullscreen mode

it receives the control to be validated, and returnsnull if its value is valid, or an error object of the form{ [error: string]: any }

Validator Factories are high-order functions that builds a Validator Function according some input parameters:

functionminLength(minLength:number):ValidatorFn{return(control:AbstractControl)=>{return(control.value&&control.value.length<minLength)?{minLength:true}// invalid:null;// valid}}
Enter fullscreen modeExit fullscreen mode

as you can see, this is a very nice way to parametrize our Functions, so we defined the provisioning of Validators (and all the other handlers) with anid and a factoryfn:

exportinterfaceDynControlValidator{id:string;fn:(...args:any[])=>ValidatorFn;}
Enter fullscreen modeExit fullscreen mode

Theid will be the string that we will use in our Configuration Object. By default,@myndpm/dyn-forms provide the default Angular Validators with the same name as we know them:required,requiredTrue,email,pattern,minLength,maxLength,min andmax.

The notation to use them in the Config Object is as follows:

// without parametersvalidators:['required'],// with parameters as arrayvalidators:['required',['min',1]],// with parameters as objectvalidators:{required:null,minLength:4},// with an inline ValidatorFn or ValidatorFn factoryvalidators:[myValidatorFn,myValidatorFactory(args)],
Enter fullscreen modeExit fullscreen mode

supporting these different notations is unexpensive and can be useful for different kind of systems or developer tastes.

Custom Validators

You can provide inline functions to build a fast prototype, but to store a plain config somewhere, you need to provide yourValidatorFn Factory with anid and afn in the respective module with a code like this:

import{AbstractControl,ValidatorFn}from'@angular/forms';import{DynFormsModule}from'@myndpm/dyn-forms';import{DynControlValidator}from'@myndpm/dyn-forms/core';constvalidators:DynControlValidator[]=[{id:'email',fn:():ValidatorFn=>{return(control:AbstractControl)=>{// implement my validator// to return { email: true } | null;}}}];@NgModule({imports:[DynFormsModule.forFeature({validators,priority:100});
Enter fullscreen modeExit fullscreen mode

note thepriority parameter to override the default validators (which weight is 0); we will play with priorities in a further article.

AsyncValidators

Providing async validators works in the same way. You provide yourfn with anid and use them in the Config Object:

createMatConfig('INPUT',{name:'quantity',validators:['required'],asyncValidators:['myAsyncValidatorId'],
Enter fullscreen modeExit fullscreen mode

and if you need to provide arguments to your AsyncValidator factory, you can use:

// single argument which can be an objectasyncValidators:[['myAsyncValidatorId',args]],// your factory will receive fn(args)// multiple arguments in array to be destructuredasyncValidators:[['myAsyncValidatorId',[arg1,arg2]]],// your factory will receive fn(arg1, arg2)
Enter fullscreen modeExit fullscreen mode

Custom Handlers

With this notation we added support for multiple kinds of functions that we require in the Dynamic Forms:Validators andAsyncValidators as we just saw,Matchers andConditions to manipulate the controls under some special requirements, and alsoParamFns to inject functions to the parameters of the DynControls too.

We will be digging into the conditional executions in the next chapter.
In the meantime, what do you think of this notation?

// PS. We are hiring!

Top comments(7)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
coffeetea profile image
Vitalii Baziuk
convert shawarma into code
  • Location
    Kyiv, Ukraine
  • Work
    Senior Developer
  • Joined
• Edited on• Edited

Liked it! Thanks for this!
Have a few questions here:

I. What if I wanna to provide a few params for one validator in array notation?
Will this be correct (range ex.):

options: { validators: ['required', ['range', [1, 5] ] ] },

II. For custom validator, if we have defined it in separate const, do we have some way to read value from other form controls somehow? Let's say I wanna validate current control value against another control value from this form. Or in that case we probably should declare custom validator in dyn form host component?


Important point: before reading this article it's nice to read this article firstdev.to/myndpm/a-new-approach-to-ha...

CollapseExpand
 
matheo profile image
Mateo Tibaquirá
Senior Angular Developer, Library Author, Open Source Advocate, Dependency Maintainer by hobby.
  • Location
    Colombia
  • Work
    Angular Solutions Architect
  • Joined

I. Yes,['range', [1, 5]] will be translated to its corresponding Factory call likefn(1, 5) and for more complex cases an object could be used like['asyncUniqueEmail', { endpoint: '...', minLength: 4, ... }] and you will receive it in your Factoryfn({ endpoint, minLength, ... }) :)

II. Let's try to implement that Validator withMatchers for the next chapter of this series:github.com/myndpm/open-source/issu...

Thank you for your feedback! :D

CollapseExpand
 
dnmakarov profile image
dnmakarov
  • Joined
• Edited on• Edited

Hey, thanks for the great article.

My question is can we apply validators to theFormGroup e.g.

formGroup = new FormGroup(  { ...fields },   { validators: [ ...someCustomValidators ] });
Enter fullscreen modeExit fullscreen mode
CollapseExpand
 
matheo profile image
Mateo Tibaquirá
Senior Angular Developer, Library Author, Open Source Advocate, Dependency Maintainer by hobby.
  • Location
    Colombia
  • Work
    Angular Solutions Architect
  • Joined

Yes, every DynControl is able to have its Validators but in the Config type structure:

{options:{validators:[...someCustomValidators]},controls:[..fieldsConfigs]}
Enter fullscreen modeExit fullscreen mode

I'm improving the typing of the Config right now to detect inlineValidatorFn in case we don't want to provide them viaid and just want to build a fast prototype :)

CollapseExpand
 
artem_shapilov profile image
Artem Shapilov
  • Location
    Ukraine
  • Work
    Frontend Developer at Mynd Property Management
  • Joined

Is it required to register validators on the module level? Does this approach has advantages over providing validators inline when creating config? e.g. when doingcreateMatConfig()

CollapseExpand
 
matheo profile image
Mateo Tibaquirá
Senior Angular Developer, Library Author, Open Source Advocate, Dependency Maintainer by hobby.
  • Location
    Colombia
  • Work
    Angular Solutions Architect
  • Joined

while implementingmatchers it was convenient to have inline functions, and in general they are nicer to implement a fast prototype without having to provide anything at module level.
I might update this article to include the inline functions in the notation. Thanks!

CollapseExpand
 
amit_dev profile image
amit
  • Joined

great work, I am trying to load all the form control from a JSON file. The below code
controls I need to fetch from a JSON(infuture may be mongoDB). I am not sure if there is a better approach, any suggestions highly appreciated.

export const simpleForm: DynFormConfig<'edit' | 'display'>  = {modeParams: {    edit: { readonly: false },    display: { readonly: true },  },  controls: [    createMatConfig('CARD', {      name: 'billing',      factory: { cssClass: 'row' },      params: {        title: 'User Details',        subtitle: 'Please fill the required fields',      },      controls: [        createMatConfig('INPUT', {          name: 'firstName',          options: { validators: ['required'] },          factory: { cssClass: 'col-sm-6 col-md-4' },          params: { label: 'First Name *' },        }),.................
Enter fullscreen modeExit fullscreen mode

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

More fromMynd.co

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp