Reputation: 115
I have used some validators in angular2 like equal password validator. In these scenarios, both two controls are in the same form and I can access both controls in a directive's validate method.
But in my scenario, Form has a one form-control with name Email
and it is required only when EmailFlag
is true. EmailFlag
is not a form-control and will update its value any time. I am handling the change value of EmailFlag
in the validator's ngOnChanges and handling change of Email
in the validate method of a validator.
I can access and set validation to form-control only when validate method get called. But on change of flag, I am unable to get form-control and set validation to it. Is there any way to get form-control on flag change and set validations?
Directive
@Directive({
selector: '[requiredIfTrue]',
providers: [{
provide: NG_VALIDATORS,
useExisting: RequiredIfTrueValidator,
multi: true
}]
})
export class RequiredIfTrueValidator implements OnChanges {
_emailFlag: boolean;
@Input('requiredIfTrue') public requiredIfTrue: boolean;
validate(control: AbstractControl): { [key: string]: any } | null {
if (this._emailFlag) {
//set validation
}
else {
//remove validation
}
}
ngOnChanges(change: SimpleChanges) {
if (change.requiredIfTrue) {
this._emailFlag = change.requiredIfTrue.currentValue;
}
}
}
component.ts
EmailFlag = false;
//flag declared and changes value time by time
component.html
<input type="text" formControlName="Email" class="form-control" [requiredIfTrue]="EmailFlag" />
Upvotes: 1
Views: 3518
Reputation: 27303
Inject NgControl inside custom directive to get FormControl diretive instance inside custom directive like this
import { Directive, OnInit, Input } from '@angular/core';
import { NgControl, Validators } from '@angular/forms';
@Directive({
selector: '[RequiredIfTrue]'
})
export class RequiredIfTrueDirective{
@Input('RequiredIfTrue') set requited(value){
console.log(value);
if(value){
this.control.control.setValidators(this.control.control.validator ? [this.control.control.validator, Validators.required] : Validators.required );
this.control.control.updateValueAndValidity();
}else{
this.control.control.clearValidators();
this.control.control.updateValueAndValidity();
}
};
constructor(private control:NgControl) {
}
}
Upvotes: 1
Reputation: 57929
If your want use a validator that depending of a variable in your .ts, you can use bind(this)
emailFlag:boolean=true;
email=new FormControl("email",this.requiredIf().bind(this))
requiredIf()
{
return (control)=>{
return this.emailFlag?!control.value?{required:true}:null:null
}
}
Be carefult, when you change the variable you need make an updateValueAndValidity
click(){
this.EmailFlag=!this.EmailFlag
this.email.updateValueAndValidity()
}
see stackblitz
NOTE: I use the way of this.requiredIf, to allow, e.g. if you has an array required=[true,false,false,true]
, to pass the "index" to the function
That's
<form [formGroup]="form">
<input formControlName="one">
<small *ngIf="form.get('one').invalid">*</small>
<button (click)="clickArray(0)">click</button>
required:{{required[0]}}<br/>
<input formControlName="two">
<small *ngIf="form.get('two').invalid">*</small>
<button (click)="clickArray(1)">click</button>
required:{{required[1]}}<br/>
<input formControlName="three">
<small *ngIf="form.get('three').invalid">*</small>
<button (click)="clickArray(2)">click</button>
required:{{required[2]}}<br/>
</form>
And you change as
form = new FormGroup({
one: new FormControl("", this.requiredIfArray(0).bind(this)),
two: new FormControl("", this.requiredIfArray(1).bind(this)),
three: new FormControl("", this.requiredIfArray(2).bind(this))
});
requiredIfArray(index) {
return control => {
return this.required[index]? !control.value? { required: true }: null: null;
};
}
Upvotes: 1
Reputation: 1684
You can force check of validity using updateValueAndValidity. You can also run it on the formGroup. See here: https://netbasal.com/three-ways-to-dynamically-alter-your-form-validation-in-angular-e5fd15f1e946
Upvotes: 0