diff --git a/lib/core/src/lib/form/components/form-renderer.component.spec.ts b/lib/core/src/lib/form/components/form-renderer.component.spec.ts index ab2bb1e438..fcc5c1fcc2 100644 --- a/lib/core/src/lib/form/components/form-renderer.component.spec.ts +++ b/lib/core/src/lib/form/components/form-renderer.component.spec.ts @@ -51,6 +51,7 @@ import { import { FormFieldModel, FormModel, TextWidgetComponent } from './widgets'; import { MatDialog } from '@angular/material/dialog'; import { of } from 'rxjs'; +import { WidgetVisibilityService } from '../services/widget-visibility.service'; const typeIntoInput = (testingUtils: UnitTestingUtils, selector: string, message: string) => { testingUtils.fillInputByCSS(selector, message); @@ -110,6 +111,48 @@ describe('Form Renderer Component', () => { 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 ', () => { 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); diff --git a/lib/core/src/lib/form/components/form-renderer.component.ts b/lib/core/src/lib/form/components/form-renderer.component.ts index 31803611d5..8b30bf11c2 100644 --- a/lib/core/src/lib/form/components/form-renderer.component.ts +++ b/lib/core/src/lib/form/components/form-renderer.component.ts @@ -16,13 +16,16 @@ */ 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 { MatButtonModule } from '@angular/material/button'; import { MatTabsModule } from '@angular/material/tabs'; import { TranslatePipe } from '@ngx-translate/core'; import { FormRulesManager, formRulesManagerFactory } from '../models/form-rules.model'; import { FormService } from '../services/form.service'; +import { WidgetVisibilityService } from '../services/widget-visibility.service'; import { FormFieldComponent } from './form-field/form-field.component'; import { FORM_FIELD_MODEL_RENDER_MIDDLEWARE, FormFieldModelRenderMiddleware } from './middlewares/middleware'; import { ContainerModel, FormFieldModel, FormModel, TabModel, RepeatWidgetComponent } from './widgets'; @@ -74,8 +77,10 @@ export class FormRendererComponent implements OnInit, OnDestroy { public readonly formService = inject(FormService); private readonly formRulesManager = inject(FormRulesManager); + private readonly visibilityService = inject(WidgetVisibilityService); private readonly dialog = inject(MatDialog); private readonly cdr = inject(ChangeDetectorRef); + private readonly destroyRef = inject(DestroyRef); @Input({ required: true }) formDefinition: FormModel; @@ -92,6 +97,13 @@ export class FormRendererComponent implements OnInit, OnDestroy { if (!this.readOnly) { 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() {