Reputation: 407
I have an array in my formcomponent class and want to be able to pass that array to a validator function. When adding multiple validators to the form, I am using Validators.compose function. This only accepts the name of the validator function though, and not any parameters to pass. Is it possible to add parameters to the function calls inside of the "compose" function?
export class ClientFormComponent
{
clientForm: ControlGroup;
npi: AbstractControl;
name: AbstractControl;
constructor(private _clientService: ClientService, _fb: FormBuilder) {
this.clientForm = _fb.group({ 'name': ['', Validators.compose([Validators.required])], 'npi': ['', Validators.compose([Validators.required, npiNumValidator, Validators.maxLength(10), Validators.minLength(10)])]});
this.name = this.clientForm.controls['name'];
this.npi = this.clientForm.controls['npi'];
}
@Input() clientList;
active = true;
onSubmit(value: Client) {
this._clientService.addDeleteClient(value, true)
.subscribe(
client => this.clientList.push(client));
}
}
function npiNumValidator(control: Control): { [s: string]: boolean } {
if (isNaN(control.value)) {
return { npiNAN: true };
}
}
Thanks for any help!
Upvotes: 13
Views: 23346
Reputation: 143
If you need to reference dynamic data from the class you can pass an object within the parameter instead of a primitive.
Example:
valParams = {
gte: 10
}
constructor(protected _fb:FormBuilder) {
this.numForm = _fb.group({
num: ['', gte(this.valParams)]
});
}
Validation Function:
export function gte(valParams: {gte:number}): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
let val: number = +control.value;
if (isNaN(val)) return { 'gte': true }
if (val <= +valParams.gte) return { 'gte': true }
return null;
}
}
Since you're passing an object JavaScript will reference the object in memory rather than an immutable primitive.
PS: As a bonus since you're passing the object reference, you can update the object directly from the validation function which can then be read by the component class.
Upvotes: 1
Reputation: 1415
The top answer meant I will have to create a class for each validator which I didn't like. Here is my approach:
public static npiNumValidator(
x: any
): (AbstractControl) => ValidationErrors | null {
return (control: AbstractControl): ValidationErrors | null => {
return !!x ? null : { error: true};
};
}
Use as:
this.form = this.formBuilder.group({
email: [undefined, [ClassName.npiNumValidator('value')]],
});
Upvotes: 0
Reputation: 657496
Just move it to a class
class NpiNumValicator {
constructor(private someField: someType) {}
npiNumValidator(control: Control): { [s: string]: boolean } {
if (isNaN(control.value)) {
return { npiNAN: true };
}
}
}
then use it like
this.clientForm = _fb.group({ 'name': ['',
Validators.compose([Validators.required])], 'npi': ['',
Validators.compose([Validators.required,
new NpiNumValidator(someArg).npiNumValidator,
Validators.maxLength(10), Validators.minLength(10)
])
]});
to be able to use this
within npiNumValidator
you can use
var npiNumVal = new NpiNumValidator(someArg);
this.clientForm = _fb.group({ 'name': ['',
Validators.compose([Validators.required])], 'npi': ['',
Validators.compose([Validators.required,
npiNumVal.npiNumValidator.bind(npiNumVal),
Validators.maxLength(10), Validators.minLength(10)
])
]});
Upvotes: 12
Reputation: 935
In some cases the data that needs to be passed to the validator is dynamic and can be found in the class that is calling the validator. In those instances I just have simply used "bind(this)" when adding the validator. Here is a formBuilder example:
this.profileFormGroups.push( this.formBuilder.group({
name: [profile.name,
Validators.compose([
Validators.required,
Validators.maxLength(30),
Validators.pattern('[a-zA-Z ]*')
]),
this.myNameValidator.bind(this)
]
}) );
}, this);
Then in your validator just reference the dynamic parameter:
//my Async Validator
myNameValidator(control: FormControl): any {
let vm = this;
return new Promise(resolve => {
if ( vm.mydynamicvalue === control.name ) { ... }
resolve({"Invalid User":true});
else
resolve(null)
});
}
Upvotes: 4
Reputation: 24945
Is it possible to add parameters to the function calls inside of the "compose" function?
Validator Declaration: straight out of Angular Code
/* Validator that requires controls to have a value of a minimum length. */
static minLength(minLength: number): ValidatorFn {
return (control: modelModule.AbstractControl): {[key: string]: any} => {
if (isPresent(Validators.required(control))) return null;
var v: string = control.value;
return v.length < minLength ?
{"minlength": {"requiredLength": minLength, "actualLength": v.length}} :
null;
};
}
Usage:
Validators.compose([Validators.minLength(4)]
NOTE: to understand it better, see How do JavaScript closures work?
Upvotes: 15
Reputation: 202216
You also leverage a method of your component to create the validation function. This way you will be able to access properties of this component using an arrow function.
Here is a sample:
@Component({ ... })
export class MyComponent {
constructor(private fb:FormBuilder) {
this.form = this.fb.group({
fieldName: [ '', this.createValidator() ]
});
}
createValidator() {
return (control) => {
var arr = this.arr;
(...)
};
}
}
Upvotes: 4