Reputation: 71
I have created own directive for adding validation and removing validation based input parameters of directive. I am getting error when loading and form field value changing validator is not working the validation
@Directive({
selector:[appdirective1],
providers:[{
provide:NG_VAILDATORS,
useExisting:forwardRef(()=>directiveName)
}]
});
export class directiveName implements OnChanges,OnInit{
@Input varName1="";
@Input varName2="";
@Input callBack1:()=>{}
@Input callBack2:()=>{}
constructor(private _injector:Injector){
}
validate1():ValidateFn{
return (control:AbstractControl):{[key:string]:any}|null =>{
//logic here
}
}
validate2():ValidateFn{
return (control:AbstractControl):{[key:string]:any}|null =>{
const obj1=this.callBack1();
//logic here
}
}
validate3():ValidateFn{
return (control:AbstractControl):{[key:string]:any}|null =>{
const obj1=this.callBack2();
//logic here
}
}
ngOnInit(){
const control=this._injector.get(NgControl);
control.control.setValidators(this.validate1);
if(this.varName1 !=="" && this.varName1 !== undefined){
control.control.setValidators(this.validate2);
}
if(this.varName2 !=="" && this.varName2 !== undefined){
control.control.setValidators(this.validate3);
}
control.control.updateValueAndValidity();
}
ngOnChanges(){
const control=this._injector.get(NgControl);
if(this.varName1 !=="" && this.varName1 !== undefined){
control.control.setValidators(this.validate2);
}
if(this.varName2 !=="" && this.varName2 !== undefined){
control.control.setValidators(this.validate3);
}
control.control.updateValueAndValidity();
}
}
}
In the html file , I have added directive selectors and input paramets
<input appdirective1 name="name2" [varName1]="success" [callBack1]="method1" />
<input appdirective1 name="name3" [varName2]="success" [callBack2]="method2"/>
Already method method1 and method2 binded in component file. I need to used this file many places.
I am getting Error like :
TypeError : validator is not a function
at Forms.mjs
at Array.map(<anonymous>)
at executeValidators(forms.mjs:896:21)
at Forms.mjs
at Array.map(<anonymous>)
at executeValidators(forms.mjs:896:21)
at Formcontrol2._ComposedValidatorsFn(forms.mjs)
at Formcontrol2._runValidator(forms.mjs)
at Formcontrol2.updateValueandValidity(forms.mjs)
Upvotes: 2
Views: 73
Reputation: 57909
The code has no logic. If you have a directive to "Validate" a control simply implements Validator.
NOTE: The error is because you forget add "multi:true" to your provider.
e.g.
@Directive({
selector: '[appdirective1]',
standalone: true,
providers: [
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => DirectiveName),
multi:true
}
],
})
export class DirectiveName implements Validator {
validate(control: AbstractControl): ValidationErrors | null {
return control.value=='Angular'?null:{ custom: true };
}
}
An unique function validate
where you add the logic.
This allow add another validators to your formControl or ngModel. Of course, forget these "ugly" setValidators, updateValueAndValidy, etc.
Upvotes: 1
Reputation: 56002
These is no need for NG_VAILDATORS
provider, since you are adding validators programatically using setValidators
and addValidators
. We use this provider when we want to autowire a validator, which is not the case in your code.
To learn more about NG_VALIDATORS try this Angular Custom Form Controls: Complete Guide article.
Instead of setValidators
you need to use addValidators
since setValidators
replaces the previous validator you had set.
control?.control?.addValidators(this.validate1());
You should always have a ngModel
or form control
configured for the elements you have this directive on, only then does NgControl
exists for usage.
<input appdirective1 name="name2" [varName1]="success" [callBack1]="method1" [formControl]="control" #controlRef="ngForm"/>
<input appdirective1 name="name3" [varName2]="success" [callBack2]="method2" [(ngModel)]="name" #modelRef="ngModel"/>
I made the repeating direcive code into it's own function for preventing code duplication.
import {
Component,
Directive,
OnChanges,
OnInit,
forwardRef,
Input,
Injector,
} from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import {
NG_VALIDATORS,
ValidatorFn,
AbstractControl,
ValidationErrors,
NgControl,
ReactiveFormsModule,
FormsModule,
FormControl,
} from '@angular/forms';
import { CommonModule } from '@angular/common';
@Directive({
selector: '[appdirective1]',
standalone: true,
})
export class directiveName implements OnChanges, OnInit {
@Input() varName1 = '';
@Input() varName2 = '';
@Input() callBack1!: (control: AbstractControl) => ValidationErrors | null;
@Input() callBack2!: (control: AbstractControl) => ValidationErrors | null;
constructor(private _injector: Injector) {}
validate1(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
//logic here
return control.value === 'Angular'
? {
invalidName: control.value,
}
: null;
};
}
validate2(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const obj1 = this.callBack1(control);
//logic here
return obj1;
};
}
validate3(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const obj1 = this.callBack2(control);
//logic here
return obj1;
};
}
ngOnInit() {
this.conditionallyAddValidators();
}
conditionallyAddValidators() {
const control = this._injector.get(NgControl);
control?.control?.addValidators(this.validate1());
if (this.varName1 !== '' && this.varName1 !== undefined) {
control?.control?.addValidators(this.validate2());
}
if (this.varName2 !== '' && this.varName2 !== undefined) {
control?.control?.addValidators(this.validate3());
}
control?.control?.updateValueAndValidity();
}
ngOnChanges() {
this.conditionallyAddValidators();
}
}
@Component({
selector: 'app-root',
standalone: true,
imports: [directiveName, ReactiveFormsModule, CommonModule, FormsModule],
template: `
<input appdirective1 name="name2" [varName1]="success" [callBack1]="method1" [formControl]="control" #controlRef="ngForm"/>
<br/>
{{controlRef.errors | json}}
<br/>
<hr/>
<input appdirective1 name="name3" [varName2]="success" [callBack2]="method2" [(ngModel)]="name" #modelRef="ngModel"/>
<br/>
{{modelRef.errors | json}}
<br/>
<hr/>
`,
})
export class App {
control = new FormControl('Angular');
name = 'Angular';
success = 'required';
method1(control: AbstractControl) {
const value = control?.value;
return value?.length <= 2
? {
minLength: true,
}
: null;
}
method2(control: AbstractControl) {
const value = control?.value;
return value?.length >= 10
? {
maxLength: true,
}
: null;
}
}
bootstrapApplication(App);
Upvotes: 0