AAE-39678 Apply visibility conditions if dependent field's value is changed with form rules (#11729)

This commit is contained in:
David Olson
2026-03-12 11:51:20 -05:00
committed by GitHub
parent a8ae3d3b4e
commit e325ad3871
2 changed files with 56 additions and 1 deletions
@@ -51,6 +51,7 @@ import {
import { FormFieldModel, FormModel, TextWidgetComponent } from './widgets'; import { FormFieldModel, FormModel, TextWidgetComponent } from './widgets';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { WidgetVisibilityService } from '../services/widget-visibility.service';
const typeIntoInput = (testingUtils: UnitTestingUtils, selector: string, message: string) => { const typeIntoInput = (testingUtils: UnitTestingUtils, selector: string, message: string) => {
testingUtils.fillInputByCSS(selector, message); testingUtils.fillInputByCSS(selector, message);
@@ -110,6 +111,48 @@ describe('Form Renderer Component', () => {
fixture.destroy(); fixture.destroy();
}); });
describe('visibility refresh on form rules', () => {
it('should refresh visibility when a fieldValueChanged rule event fires for the same form', () => {
const form = formService.parseForm(textWidgetVisibility.formRepresentation);
formRendererComponent.formDefinition = form;
fixture.detectChanges();
const visibilityService = TestBed.inject(WidgetVisibilityService);
const refreshVisibilitySpy = spyOn(visibilityService, 'refreshVisibility');
formService.formRulesEvent.next({ type: 'fieldValueChanged', form } as any);
expect(refreshVisibilitySpy).toHaveBeenCalledOnceWith(form);
});
it('should not refresh visibility when a fieldValueChanged rule event fires for a different form', () => {
const form = formService.parseForm(textWidgetVisibility.formRepresentation);
const otherForm = formService.parseForm(formDateVisibility.formRepresentation);
formRendererComponent.formDefinition = form;
fixture.detectChanges();
const visibilityService = TestBed.inject(WidgetVisibilityService);
const refreshVisibilitySpy = spyOn(visibilityService, 'refreshVisibility');
formService.formRulesEvent.next({ type: 'fieldValueChanged', form: otherForm } as any);
expect(refreshVisibilitySpy).not.toHaveBeenCalled();
});
it('should not refresh visibility for non-fieldValueChanged rule events', () => {
const form = formService.parseForm(textWidgetVisibility.formRepresentation);
formRendererComponent.formDefinition = form;
fixture.detectChanges();
const visibilityService = TestBed.inject(WidgetVisibilityService);
const refreshVisibilitySpy = spyOn(visibilityService, 'refreshVisibility');
formService.formRulesEvent.next({ type: 'formLoaded', form } as any);
expect(refreshVisibilitySpy).not.toHaveBeenCalled();
});
});
describe('Display Date Widget ', () => { describe('Display Date Widget ', () => {
it('Should be able to see a widget when the visibility condition refers to another fields with specific date', async () => { it('Should be able to see a widget when the visibility condition refers to another fields with specific date', async () => {
formRendererComponent.formDefinition = formService.parseForm(formDateVisibility.formRepresentation.formDefinition); formRendererComponent.formDefinition = formService.parseForm(formDateVisibility.formRepresentation.formDefinition);
@@ -16,13 +16,16 @@
*/ */
import { NgClass, NgForOf, NgIf, NgStyle, NgTemplateOutlet } from '@angular/common'; import { NgClass, NgForOf, NgIf, NgStyle, NgTemplateOutlet } from '@angular/common';
import { ChangeDetectorRef, Component, inject, Injector, Input, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; import { ChangeDetectorRef, Component, DestroyRef, inject, Injector, Input, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { filter } from 'rxjs';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatTabsModule } from '@angular/material/tabs'; import { MatTabsModule } from '@angular/material/tabs';
import { TranslatePipe } from '@ngx-translate/core'; import { TranslatePipe } from '@ngx-translate/core';
import { FormRulesManager, formRulesManagerFactory } from '../models/form-rules.model'; import { FormRulesManager, formRulesManagerFactory } from '../models/form-rules.model';
import { FormService } from '../services/form.service'; import { FormService } from '../services/form.service';
import { WidgetVisibilityService } from '../services/widget-visibility.service';
import { FormFieldComponent } from './form-field/form-field.component'; import { FormFieldComponent } from './form-field/form-field.component';
import { FORM_FIELD_MODEL_RENDER_MIDDLEWARE, FormFieldModelRenderMiddleware } from './middlewares/middleware'; import { FORM_FIELD_MODEL_RENDER_MIDDLEWARE, FormFieldModelRenderMiddleware } from './middlewares/middleware';
import { ContainerModel, FormFieldModel, FormModel, TabModel, RepeatWidgetComponent } from './widgets'; import { ContainerModel, FormFieldModel, FormModel, TabModel, RepeatWidgetComponent } from './widgets';
@@ -74,8 +77,10 @@ export class FormRendererComponent<T> implements OnInit, OnDestroy {
public readonly formService = inject(FormService); public readonly formService = inject(FormService);
private readonly formRulesManager = inject(FormRulesManager<T>); private readonly formRulesManager = inject(FormRulesManager<T>);
private readonly visibilityService = inject(WidgetVisibilityService);
private readonly dialog = inject(MatDialog); private readonly dialog = inject(MatDialog);
private readonly cdr = inject(ChangeDetectorRef); private readonly cdr = inject(ChangeDetectorRef);
private readonly destroyRef = inject(DestroyRef);
@Input({ required: true }) @Input({ required: true })
formDefinition: FormModel; formDefinition: FormModel;
@@ -92,6 +97,13 @@ export class FormRendererComponent<T> implements OnInit, OnDestroy {
if (!this.readOnly) { if (!this.readOnly) {
this.formRulesManager.initialize(this.formDefinition); this.formRulesManager.initialize(this.formDefinition);
} }
this.formService.formRulesEvent
.pipe(
filter((event) => event?.type === 'fieldValueChanged' && event.form?.id === this.formDefinition?.id),
takeUntilDestroyed(this.destroyRef)
)
.subscribe(() => this.visibilityService.refreshVisibility(this.formDefinition));
} }
ngOnDestroy() { ngOnDestroy() {