Scenario:
Initially I have one text box(Name1
), one date picker(DOB1
) and a check box (Compare
). Both Name1
and DOB1
are required. When check box is clicked, two more form controls are dynamically added named as Name2
and DOB2
and either any one of Name1
or DOB2
are required.
so the valid form is having any of
Name1
DOB1
Name2
or //If Name2
is valid then need to remove required validator from DOB2
Name1
DOB1
DOB2
or //If DOB2
is valid then need to remove required validator from Name2
Name1
DOB1
Name2
DOB2
In all the above cases, the form is valid show enable the submit button.
Issue:
I had tried using setValidators but still couldn't figure out what i'm missing. When I click the checkbox, the form is valid only when all four controls are valid. I just need any three of them valid.
Code:
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
<ion-card class="person1">
<ion-card-content>
<ion-list lines="full" class="ion-no-margin ion-no-padding">
<ion-item>
<ion-label position="stacked">Name / Number <ion-text color="danger">*</ion-text>
</ion-label>
<ion-input type="text" formControlName="NameNumber"></ion-input>
</ion-item>
<ion-item>
<ion-label position="stacked">Date of birth<ion-text color="danger">*</ion-text>
</ion-label>
<ion-datetime required placeholder="Select Date" formControlName="DateOfBirth"></ion-datetime>
</ion-item>
</ion-list>
</ion-card-content>
</ion-card>
<ion-card class="person2" *ngIf="isComparisonChecked">
<ion-card-content>
<ion-list lines="full" class="ion-no-margin ion-no-padding">
<ion-item>
<ion-label position="stacked">Name / Number <ion-text color="danger">*</ion-text>
</ion-label>
<ion-input type="text" formControlName="NameNumber2"></ion-input>
</ion-item>
<ion-item>
<ion-label position="stacked">Date of birth<ion-text color="danger">*</ion-text>
</ion-label>
<ion-datetime required placeholder="Select Date" formControlName="DateOfBirth2"></ion-datetime>
</ion-item>
</ion-list>
</ion-card-content>
</ion-card>
<ion-item class="compare-section" lines="none">
<ion-label>Compare</ion-label>
<ion-checkbox color="danger" formControlName="IsCompare"></ion-checkbox>
</ion-item>
<div class="ion-padding">
<ion-button color="danger" *ngIf="LicensedStatus" [disabled]="!this.profileForm.valid" expand="block"
type="submit" class="ion-no-margin">Submit</ion-button>
</div>
</form>
Ts:
profileForm = new FormGroup({
NameNumber: new FormControl('', [Validators.required, Validators.pattern('^[A-Za-z0-9 _]*[A-Za-z0-9][A-Za-z0-9 _]*$')]),
DateOfBirth: new FormControl('', Validators.required),
IsCompare: new FormControl(false)
});
...
this.profileForm.get('IsCompare').valueChanges.subscribe(checked => {
if (checked) {
this.profileForm.addControl('NameNumber2', new FormControl('', [Validators.required, Validators.pattern('^[A-Za-z0-9 _]*[A-Za-z0-9][A-Za-z0-9 _]*$')]));
this.profileForm.addControl('DateOfBirth2', new FormControl('', Validators.required));
this.profileForm.get('NameNumber2').valueChanges.subscribe(() => {
if (this.profileForm.get('NameNumber2').valid) {
this.profileForm.get('DateOfBirth2').clearValidators();
}
else {
this.profileForm.get('DateOfBirth2').setValidators([Validators.required]);
}
this.profileForm.get('DateOfBirth2').updateValueAndValidity();
});
this.profileForm.get('DateOfBirth2').valueChanges.subscribe(() => {
if (this.profileForm.get('DateOfBirth2').valid) {
this.profileForm.get('NameNumber2').clearValidators();
}
else {
this.profileForm.get('NameNumber2').setValidators([Validators.required, Validators.pattern('^[A-Za-z0-9 _]*[A-Za-z0-9][A-Za-z0-9 _]*$')]);
}
this.profileForm.get('NameNumber2').updateValueAndValidity();
});
}
else {
this.profileForm.removeControl('NameNumber2');
this.profileForm.removeControl('DateOfBirth2');
}
});
What am I missing here?
Update #1:
I have updated the above code. If I use updateValueAndValidity
i'm getting this error in the console
This is happening because updateValueAndValidity()
emits another valueChanges
event. So your subscriptions trigger each other infinitely.
this.profileForm.get('NameNumber2').valueChanges.subscribe(() => {
// omitted
this.profileForm.get('DateOfBirth2').updateValueAndValidity(); // Triggers valueChanges for 'DateOfBirth2'
});
this.profileForm.get('DateOfBirth2').valueChanges.subscribe(() => {
// omitted
this.profileForm.get('NameNumber2').updateValueAndValidity(); // Triggers valueChanges for 'NameNumber2'
});
One way to avoid this is already described in previous posts: Using distinctUntilChanged
.
A cleaner way is built into the method itself though: updateValueAndValidity()
takes an object to configure its behaviour. updateValueAndValidity({emitEvent: false})
will prevent the valueChanges
event to be emitted and thus stop the event loop.
this.profileForm.get('NameNumber2').valueChanges.subscribe(() => {
// omitted
this.profileForm.get('DateOfBirth2').updateValueAndValidity({emitEvent:false}); // Does NOT trigger valueChanges
});
this.profileForm.get('DateOfBirth2').valueChanges.subscribe(() => {
// omitted
this.profileForm.get('NameNumber2').updateValueAndValidity({emitEvent:false}); // Does NOT trigger valueChanges
});