I was checking this question and its answers in order to post.
public isFirst = false;
public isSecond = false;
private buildFormGroup() {
const internalFormGroup = this.formBuilder.group({
idTypeCode: ['', [Validators.required, Validators.min(1)]],
master: [true],
slave: [''],
fieldSlave: [''], // Validations depends indirectly on idTypeCode !!! HERE
});
return internalFormGroup;
}
private conditionalValidator(masterName: string, masterValue: any, slaveName: string, validators: any) {
if (this.formGroup) {
const masterControl = this.formGroup.get(masterName);
if (masterControl) {
masterControl.valueChanges.subscribe((value) => {
const slaveControl = this.formGroup.get(slaveName);
if (slaveControl) {
if (value === masterValue) {
slaveControl.setValidators(validators);
} else {
slaveControl.clearValidators();
}
slaveControl.updateValueAndValidity();
}
});
}
}
}
public onTypeCodeChange(event: MatSelectChange) {
const selectedId = event;
const selectedTypeCode = this.typeCodes.find((typeCode) => typeCode.id === selectedId);
this.isFirst = selectedTypeCode?.codeEnum === CodeEnum.First;
this.isSecond = selectedTypeCode?.codeEnum === CodeEnum.Second;
}
I skip the code that fills the observable typeCodes$
public readonly typeCodes$: Observable<TypeCodeDto[]>;
private typeCodes: TypeCodeDto[] = [];
public ngOnInit(): void {
this.typeCodes$.subscribe((typeCodes) => {
this.typeCodes = typeCodes;
});
this.conditionalValidator('master', false, 'slave', [Validators.required, Validators.min(1)]);
}
As you can see the use of conditionalValidator
method was easy!!!.
But, I have an interface that includes one Enum
export interface TypeCodeDto {
id?: number;
name?: string;
codeEnum?: CodeEnum;
}
export enum CodeEnum {
None = 0,
First = 1,
Second = 2,
}
In my HTML, I'm using a Select
with the previous observable typeCodes$
<mat-select
formControlName="idTypeCode"
[required]="formGroup.controls.idTypeCode.invalid"
(ngModelChange)="onTypeCodeChange($event)"
>
<mat-option *ngFor="let typeCode of typeCodes$ | async" [value]="typeCode.id">
{{ typeCode.name }}
</mat-option>
</mat-select>
Now I have an complex situation, in my HTML when the Select
(or idTypeCode
) correspond to one TypeCodeDto
with codeEnum
equals to Second
I need to apply:
fieldSlave: ['', [Validators.required, Validators.maxLength(256), Validators.minLength(1)]],
How to implement that?
CodePudding user response:
Add one observable:
private subCodeEnum = new Subject<CodeEnum>();
In your method!
public onTypeCodeChange(event: MatSelectChange) {
const selectedId = event;
const selectedTypeCode = this.typeCodes.find(
(typeCode) => typeCode.id === selectedId
);
this.subCodeEnum.next(selectedTypeCode?.codeEnum);
}
Create (or replace the code of your conditionalValidator
method):
private conditionalObservableValidator(
masterObservable: Observable<any> | null,
masterValue: any,
slaveControl: AbstractControl | null,
trueValidators: ValidatorFn | ValidatorFn[] | null,
falseValidators?: ValidatorFn | ValidatorFn[] | null
) {
if (slaveControl && masterObservable) {
masterObservable.subscribe(
(value) => {
if (value === masterValue) {
slaveControl.setValidators(trueValidators);
} else {
slaveControl.setValidators(falseValidators);
}
slaveControl.updateValueAndValidity();
}
);
}
}
How to use it?
public ngOnInit(): void {
//
this.conditionalObservableValidator(
this.formGroup.get('master').valueChanges,
false,
this.formGroup.get('slave'),
[Validators.required, Validators.min(1),]
);
this.conditionalObservableValidator(
this.subCodeEnum,
CodeEnum.Second,
this.formGroup.get('fieldSlave'),
[Validators.required, Validators.maxLength(256), Validators.minLength(1)],
null // Last argument is Not necessary
);
}