VahiD
VahiD

Reputation: 1064

Angular reactive forms, validating one form based on a FormControl on another form

Consider I have two forms on the page, and implemented a wizard like stepper, and have put each of my forms on the stepper's each steps. Now I want to make a field on second form required, if certain value in first form selected.

see below code, the rechargeCode in second form, is related to the operator which is selected in first form. and if some specific operator selected, the rechargeCode should be mandatory.

<mat-vertical-stepper class="mat-elevation-z4" [linear]="true">
<mat-step [stepControl]="verticalStepperStep1">
    <div fxLayout="row" fxLayoutAlign="center">
         <form fxLayout="column" [formGroup]="verticalStepperStep1" fxFlex="50">
            <ng-template matStepLabel>operator select</ng-template>
            <div fxFlex="1 1 auto" fxLayout="column">
                <mat-form-field appearance="" class="right-align" fxFlex="100">
                    <mat-label>operator</mat-label>
                    <mat-select formControlName="operator" (selectionChange)="operatorChanged()" required>
                        <mat-option *ngFor="let item of operatorList" value="{{item.value}}">
                            {{item.name}}
                        </mat-option>
                    </mat-select>
                </mat-form-field>
            </div>
            <div fxLayout="row" fxLayoutAlign="center center">
                <button fxFlex="20" fxFlex.lt-md="50" mat-raised-button matStepperNext type="button" color="accent">
                    next
                </button>
            </div>
        </form>
    </div>
</mat-step>

<mat-step [stepControl]="verticalStepperStep2">
    <div fxLayout="row" fxLayoutAlign="center">
        <form fxLayout="column" [formGroup]="verticalStepperStep2" fxFlex="50">
            <ng-template matStepLabel>mobile number</ng-template>
            <div fxFlex="1 0 auto" fxLayout="row" fxLayoutAlign="center">
                <mat-form-field appearance="" class="right-align" fxFlex="100">
                    <mat-label>mobile number</mat-label>
                    <input matInput type="tel" formControlName="msisdn" required>
                </mat-form-field>
                <mat-form-field class="right-align" fxFlex="100">
                    <mat-select formControlName="rechargeCode">
                        <mat-option *ngFor="let item of rechargeCodeList" value="{{item.value}}">
                            {{item.name}}
                        </mat-option>
                    </mat-select>
                </mat-form-field>
            </div>
            <div fxLayout="row" fxLayoutAlign="center center">
                <button fxFlex="20" fxFlex.lt-md="50" mat-raised-button matStepperPrevious type="button" color="accent">
                    previous
                </button>
                <button fxFlex="20" fxFlex.lt-md="50" mat-raised-button matStepperNext type="button" color="accent">
                    next
                </button>
            </div>
        </form>
    </div>
</mat-step>
<mat-step>
    <ng-template matStepLabel>final step</ng-template>
    <div class="h2 m-16" fxLayout="row" fxLayoutAlign="center center">
        <div class="card-preview">
            <div class="fuse-card">
                <div class="p-16">
                    <div class="h1">final</div>
                </div>
                <div class="card-divider"></div>
                <div class="p-16 pt-4">
                    <div class="mb-12" fxLayout="row" fxLayoutAlign="space-between center">
                        <div>
                            <div *ngIf="this.verticalStepperStep2.get('msisdn')" class="h2 secondary-text">شماره موبایل: {{this.verticalStepperStep2.get('msisdn').value}}</div>
                        </div>
                    </div>
                    <div class="mb-12" fxLayout="row" fxLayoutAlign="space-between center">
                        <div>
                            <div *ngIf="this.verticalStepperStep1.get('amount')" class="h2 secondary-text">مبلغ قابل پرداخت: {{this.verticalStepperStep1.get('amount').value}} ريال</div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</mat-step>

what can I do?

Upvotes: 1

Views: 732

Answers (1)

Artyom Amiryan
Artyom Amiryan

Reputation: 2966

there are many options, for example you can check first form's field and use setVAlidataors for second form to assign new validator, for example

if (this.firstForm.get('formControlThatYouNeed').value) {
    this.secondForm.get('formControlYouNeedToUpdate').setValidators([Validator.required]);
}

don't forget to include other validators(if you have for this control) in setVAlidataors array as this method removes old validators. Also you can create custom Validator for example

customValidator(firstFormFieldValue: any): ValidatorFn {
    return (control: AbstractControl | null) => {
        if (firstFormFieldValue.notSelected) {
            return null;
        }

        const error = Validators.required(control);
        if (error) {
           const firstError = Object.keys(error)[0];
           return { [firstError]: { message } };
        }
        return null;
    }
}

and use it like so

this.fb.group({
      field: ['fieldValue', [this.customValidator(this.firstFormFieldValue)]],
}));

Upvotes: 1

Related Questions