diff --git a/lib/core/form/components/form-field/form-field.component.spec.ts b/lib/core/form/components/form-field/form-field.component.spec.ts
index 0409c6a27a..147d7aa3e9 100644
--- a/lib/core/form/components/form-field/form-field.component.spec.ts
+++ b/lib/core/form/components/form-field/form-field.component.spec.ts
@@ -113,7 +113,8 @@ describe('FormFieldComponent', () => {
component.field.isVisible = false;
fixture.detectChanges();
fixture.whenStable().then(() => {
- expect(fixture.nativeElement.querySelector('#field-FAKE-TXT-WIDGET-container').hidden).toBeTruthy();
+ const debugElement = fixture.nativeElement.querySelector('#field-FAKE-TXT-WIDGET-container').style.visibility;
+ expect(debugElement).toEqual('hidden');
done();
});
});
@@ -128,7 +129,7 @@ describe('FormFieldComponent', () => {
fixture.detectChanges();
fixture.whenStable().then(() => {
- expect(fixture.nativeElement.querySelector('#field-FAKE-TXT-WIDGET-container').hidden).toBeFalsy();
+ expect(fixture.nativeElement.querySelector('#field-FAKE-TXT-WIDGET-container').style.visibility).toEqual('visible');
done();
});
});
@@ -141,10 +142,10 @@ describe('FormFieldComponent', () => {
component.field = field;
fixture.detectChanges();
- expect(fixture.nativeElement.querySelector('#field-FAKE-TXT-WIDGET-container').hidden).toBeFalsy();
+ expect(fixture.nativeElement.querySelector('#field-FAKE-TXT-WIDGET-container').style.visibility).toEqual('visible');
component.field.isVisible = false;
fixture.detectChanges();
- expect(fixture.nativeElement.querySelector('#field-FAKE-TXT-WIDGET-container').hidden).toBeTruthy();
+ expect(fixture.nativeElement.querySelector('#field-FAKE-TXT-WIDGET-container').style.visibility).toEqual('hidden');
});
it('[C213878] - Should fields be correctly rendered when filled with process variables', async () => {
diff --git a/lib/core/form/components/form-field/form-field.component.ts b/lib/core/form/components/form-field/form-field.component.ts
index 49ef7bc62b..27a0530e24 100644
--- a/lib/core/form/components/form-field/form-field.component.ts
+++ b/lib/core/form/components/form-field/form-field.component.ts
@@ -40,7 +40,7 @@ declare const adf: any;
selector: 'adf-form-field',
template: `
diff --git a/lib/core/form/components/form-renderer.component.spec.ts b/lib/core/form/components/form-renderer.component.spec.ts
index 57766a4748..a9d195b38c 100644
--- a/lib/core/form/components/form-renderer.component.spec.ts
+++ b/lib/core/form/components/form-renderer.component.spec.ts
@@ -43,6 +43,7 @@ import { FormRenderingService } from '../services/form-rendering.service';
import { TextWidgetComponent } from './widgets';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
+import { FormRulesManager } from '../models/form-rules.model';
const typeIntoInput = (targetInput: HTMLInputElement, message: string) => {
expect(targetInput).toBeTruthy('Expected input to set to be valid and not null');
@@ -57,12 +58,12 @@ const typeIntoDate = (targetInput: DebugElement, date: { srcElement: { value: st
const expectElementToBeHidden = (targetElement: HTMLElement): void => {
expect(targetElement).toBeTruthy();
- expect(targetElement.hidden).toBe(true, `${targetElement.id} should be hidden but it is not`);
+ expect(targetElement.style.visibility).toBe('hidden', `${targetElement.id} should be hidden but it is not`);
};
const expectElementToBeVisible = (targetElement: HTMLElement): void => {
expect(targetElement).toBeTruthy();
- expect(targetElement.hidden).toBe(false, `${targetElement.id} should be visibile but it is not`);
+ expect(targetElement.style.visibility).not.toBe('hidden', `${targetElement.id} should be visibile but it is not`);
};
const expectInputElementValueIs = (targetElement: HTMLInputElement, value: string): void => {
@@ -70,22 +71,23 @@ const expectInputElementValueIs = (targetElement: HTMLInputElement, value: strin
expect(targetElement.value).toBe(value, `invalid value for ${targetElement.name}`);
};
-const expectElementToBeInvalid = (fieldId: string, fixture: ComponentFixture
): void => {
+const expectElementToBeInvalid = (fieldId: string, fixture: ComponentFixture>): void => {
const invalidElementContainer = fixture.nativeElement.querySelector(`#field-${fieldId}-container .adf-invalid`);
expect(invalidElementContainer).toBeTruthy();
};
-const expectElementToBeValid = (fieldId: string, fixture: ComponentFixture): void => {
+const expectElementToBeValid = (fieldId: string, fixture: ComponentFixture>): void => {
const invalidElementContainer = fixture.nativeElement.querySelector(`#field-${fieldId}-container .adf-invalid`);
expect(invalidElementContainer).toBeFalsy();
};
describe('Form Renderer Component', () => {
- let formRendererComponent: FormRendererComponent;
- let fixture: ComponentFixture;
+ let formRendererComponent: FormRendererComponent;
+ let fixture: ComponentFixture>;
let formService: FormService;
let formRenderingService: FormRenderingService;
+ let rulesManager: FormRulesManager;
setupTestBed({
imports: [
@@ -100,6 +102,7 @@ describe('Form Renderer Component', () => {
formRendererComponent = fixture.componentInstance;
formService = TestBed.inject(FormService);
formRenderingService = TestBed.inject(FormRenderingService);
+ rulesManager = fixture.debugElement.injector.get(FormRulesManager);
});
afterEach(() => {
@@ -659,4 +662,24 @@ describe('Form Renderer Component', () => {
});
});
+
+ describe('Form rules', () => {
+ it('should call the Form Rules Manager init on component changes', () => {
+ spyOn(rulesManager, 'initialize');
+ const formModel = formService.parseForm(customWidgetFormWithVisibility.formRepresentation.formDefinition);
+
+ formRendererComponent.formDefinition = formModel;
+ formRendererComponent.ngOnChanges();
+
+ expect(rulesManager.initialize).toHaveBeenCalledWith(formModel);
+ });
+
+ it('should call the Form Rules Manager destroy on component destruction', () => {
+ spyOn(rulesManager, 'destroy');
+
+ formRendererComponent.ngOnDestroy();
+
+ expect(rulesManager.destroy).toHaveBeenCalled();
+ });
+ });
});
diff --git a/lib/core/form/components/form-renderer.component.ts b/lib/core/form/components/form-renderer.component.ts
index 1deb4323fe..3b8ecddca3 100644
--- a/lib/core/form/components/form-renderer.component.ts
+++ b/lib/core/form/components/form-renderer.component.ts
@@ -15,16 +15,24 @@
* limitations under the License.
*/
-import { Component, ViewEncapsulation, Input } from '@angular/core';
+import { Component, ViewEncapsulation, Input, OnDestroy, Injector, OnChanges } from '@angular/core';
+import { FormRulesManager, formRulesManagerFactory } from '../models/form-rules.model';
import { FormModel } from './widgets/core/form.model';
@Component({
selector: 'adf-form-renderer',
templateUrl: './form-renderer.component.html',
styleUrls: ['./form-renderer.component.scss'],
- encapsulation: ViewEncapsulation.None
+ encapsulation: ViewEncapsulation.None,
+ providers: [
+ {
+ provide: FormRulesManager,
+ useFactory: formRulesManagerFactory,
+ deps: [Injector]
+ }
+ ]
})
-export class FormRendererComponent {
+export class FormRendererComponent implements OnChanges, OnDestroy {
/** Toggle debug options. */
@Input()
@@ -35,4 +43,14 @@ export class FormRendererComponent {
debugMode: boolean;
+ constructor(private formRulesManager: FormRulesManager) { }
+
+ ngOnChanges(): void {
+ this.formRulesManager.initialize(this.formDefinition);
+ }
+
+ ngOnDestroy() {
+ this.formRulesManager.destroy();
+ }
+
}
diff --git a/lib/core/form/components/widgets/core/form.model.spec.ts b/lib/core/form/components/widgets/core/form.model.spec.ts
index 617db89bff..44be53d7b5 100644
--- a/lib/core/form/components/widgets/core/form.model.spec.ts
+++ b/lib/core/form/components/widgets/core/form.model.spec.ts
@@ -24,7 +24,7 @@ import { FormFieldModel } from './form-field.model';
import { FormOutcomeModel } from './form-outcome.model';
import { FormModel } from './form.model';
import { TabModel } from './tab.model';
-import { fakeMetadataForm, fakeViewerForm } from 'process-services-cloud/src/lib/form/mocks/cloud-form.mock';
+import { cloudFormMock, fakeMetadataForm, fakeViewerForm } from 'process-services-cloud/src/lib/form/mocks/cloud-form.mock';
import { Node } from '@alfresco/js-api';
import { UploadWidgetContentLinkModel } from './upload-widget-content-link.model';
import { AlfrescoApiService } from '../../../../services';
@@ -607,8 +607,8 @@ describe('FormModel', () => {
expect(form.values['pfx_property_one']).toBe('testValue');
expect(form.values['pfx_property_two']).toBe(true);
- expect(form.values['pfx_property_three']).toEqual({ id: 'opt_1', name: 'Option 1'});
- expect(form.values['pfx_property_four']).toEqual({ id: 'option_2', name: 'Option: 2'});
+ expect(form.values['pfx_property_three']).toEqual({ id: 'opt_1', name: 'Option 1' });
+ expect(form.values['pfx_property_four']).toEqual({ id: 'option_2', name: 'Option: 2' });
expect(form.values['pfx_property_five']).toEqual('green');
expect(form.values['pfx_property_six']).toEqual('text-value');
expect(form.values['pfx_property_seven']).toBeNull();
@@ -649,4 +649,53 @@ describe('FormModel', () => {
expect(form.values['cmfb85b2a7295ba41209750bca176ccaf9a']).toBeNull();
});
});
+
+ describe('Form actions', () => {
+
+ let form: FormModel;
+ let fieldId: string;
+ let field: FormFieldModel;
+
+ beforeEach(() => {
+ form = new FormModel(cloudFormMock);
+ fieldId = 'text1';
+ field = form.getFieldById(fieldId);
+ });
+
+ it('should change field visibility', () => {
+ const originalValue = field.isVisible;
+
+ form.changeFieldVisibility(fieldId, !originalValue);
+
+ expect(field.isVisible).toEqual(!originalValue);
+ });
+
+ it('should change field disabled', () => {
+ const originalValue = field.readOnly;
+
+ form.changeFieldDisabled(fieldId, !originalValue);
+
+ expect(field.readOnly).toEqual(!originalValue);
+ });
+
+ it('should change field required', () => {
+ const originalValue = field.required;
+
+ form.changeFieldRequired(fieldId, !originalValue);
+
+ expect(field.required).toEqual(!originalValue);
+ });
+
+ it('should change field value', () => {
+ form.changeFieldValue(fieldId, 'newValue');
+
+ expect(field.value).toEqual('newValue');
+ });
+
+ it('should change variable value', () => {
+ form.changeVariableValue('FormVarStrId', 'newValue');
+
+ expect(form.getFormVariable('FormVarStrId').value).toEqual('newValue');
+ });
+ });
});
diff --git a/lib/core/form/components/widgets/core/form.model.ts b/lib/core/form/components/widgets/core/form.model.ts
index 4f63c5dc80..13ed152a43 100644
--- a/lib/core/form/components/widgets/core/form.model.ts
+++ b/lib/core/form/components/widgets/core/form.model.ts
@@ -33,6 +33,7 @@ import { FormFieldTemplates } from './form-field-templates';
import { UploadWidgetContentLinkModel } from './upload-widget-content-link.model';
import { FormValidationService } from '../../../services/form-validation-service.interface';
import { ProcessFormModel } from './process-form-model.interface';
+import { WidgetTypeEnum, WidgetVisibilityModel } from '../../../models/widget-visibility.model';
export interface FormRepresentationModel {
[key: string]: any;
@@ -419,4 +420,44 @@ export class FormModel implements ProcessFormModel {
viewer.value = viewer.parseValue(viewer.json);
});
}
+
+ changeFieldVisibility(fieldId: string, visibility: boolean): void {
+ const visibilityRule: WidgetVisibilityModel = new WidgetVisibilityModel();
+
+ const field = this.getFieldById(fieldId);
+ if (!!field) {
+ visibilityRule.operator = visibility ? 'empty' : '!empty';
+ visibilityRule.leftType = WidgetTypeEnum.field;
+ field.visibilityCondition = visibilityRule;
+ field.isVisible = false;
+ }
+ }
+
+ changeFieldDisabled(fieldId: string, disabled: boolean): void {
+ const field = this.getFieldById(fieldId);
+ if (!!field) {
+ field.readOnly = this.readOnly || disabled;
+ }
+ }
+
+ changeFieldRequired(fieldId: string, required: boolean): void {
+ const field = this.getFieldById(fieldId);
+ if (!!field) {
+ field.required = required;
+ }
+ }
+
+ changeFieldValue(fieldId: string, value: any): void {
+ const field = this.getFieldById(fieldId);
+ if (!!field) {
+ field.value = value;
+ }
+ }
+
+ changeVariableValue(variableId: string, value: any): void {
+ const variable = this.getFormVariable(variableId);
+ if (!!variable) {
+ variable.value = value;
+ }
+ }
}
diff --git a/lib/core/form/components/widgets/widget.component.spec.ts b/lib/core/form/components/widgets/widget.component.spec.ts
index 6f61ff386e..6104246a33 100644
--- a/lib/core/form/components/widgets/widget.component.spec.ts
+++ b/lib/core/form/components/widgets/widget.component.spec.ts
@@ -54,7 +54,16 @@ describe('WidgetComponent', () => {
element.click();
});
- });
+
+ it('should click event be redirect on the form rules event service', (done) => {
+ widget.formService.formRulesEvent.subscribe((event) => {
+ expect(event.type).toEqual('click');
+ done();
+ });
+
+ element.click();
+ });
+ });
it('should check field', () => {
expect(widget.hasField()).toBeFalsy();
@@ -64,7 +73,7 @@ describe('WidgetComponent', () => {
it('should send an event after view init', (done) => {
const fakeForm = new FormModel();
- const fakeField = new FormFieldModel(fakeForm, {id: 'fakeField', value: 'fakeValue'});
+ const fakeField = new FormFieldModel(fakeForm, { id: 'fakeField', value: 'fakeValue' });
widget.field = fakeField;
widget.fieldChanged.subscribe((field) => {
@@ -79,7 +88,7 @@ describe('WidgetComponent', () => {
it('should send an event when a field is changed', (done) => {
const fakeForm = new FormModel();
- const fakeField = new FormFieldModel(fakeForm, {id: 'fakeField', value: 'fakeValue'});
+ const fakeField = new FormFieldModel(fakeForm, { id: 'fakeField', value: 'fakeValue' });
widget.fieldChanged.subscribe((field) => {
expect(field).not.toBe(null);
expect(field.id).toBe('fakeField');
@@ -96,10 +105,10 @@ describe('WidgetComponent', () => {
widget.field = new FormFieldModel(null);
expect(widget.isRequired()).toBeFalsy();
- widget.field = new FormFieldModel(null, {required: false});
+ widget.field = new FormFieldModel(null, { required: false });
expect(widget.isRequired()).toBeFalsy();
- widget.field = new FormFieldModel(null, {required: true});
+ widget.field = new FormFieldModel(null, { required: true });
expect(widget.isRequired()).toBeTruthy();
});
});
diff --git a/lib/core/form/components/widgets/widget.component.ts b/lib/core/form/components/widgets/widget.component.ts
index 53dcd838ed..d2dbbdc6cd 100644
--- a/lib/core/form/components/widgets/widget.component.ts
+++ b/lib/core/form/components/widgets/widget.component.ts
@@ -18,6 +18,8 @@
/* eslint-disable @angular-eslint/component-selector */
import { AfterViewInit, Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core';
+import { FormFieldEvent } from '../../events/form-field.event';
+import { FormRulesEvent } from '../../events/form-rules.event';
import { FormService } from './../../services/form.service';
import { FormFieldModel } from './core/index';
@@ -106,6 +108,7 @@ export class WidgetComponent implements AfterViewInit {
event(event: Event): void {
this.formService.formEvents.next(event);
+ this.formService.formRulesEvent.next(new FormRulesEvent(event?.type, new FormFieldEvent(this.field?.form, this.field), event));
}
markAsTouched() {
diff --git a/lib/core/form/events/form-rules.event.ts b/lib/core/form/events/form-rules.event.ts
new file mode 100644
index 0000000000..0cba4f64af
--- /dev/null
+++ b/lib/core/form/events/form-rules.event.ts
@@ -0,0 +1,32 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { FormFieldEvent } from './form-field.event';
+import { FormEvent } from './form.event';
+
+export class FormRulesEvent extends FormFieldEvent {
+
+ readonly type: string;
+ readonly event: Event;
+
+ constructor(type: string, formEvent: FormEvent, event?: Event) {
+ super(formEvent.form, formEvent['field']);
+ this.type = type;
+ this.event = event;
+ }
+
+}
diff --git a/lib/core/form/events/index.ts b/lib/core/form/events/index.ts
index 0194d7b9fe..ba2617e5d4 100644
--- a/lib/core/form/events/index.ts
+++ b/lib/core/form/events/index.ts
@@ -21,3 +21,4 @@ export * from './form-field.event';
export * from './validate-form-field.event';
export * from './validate-form.event';
export * from './validate-dynamic-table-row.event';
+export * from './form-rules.event';
diff --git a/lib/core/form/models/form-rules.model.spec.ts b/lib/core/form/models/form-rules.model.spec.ts
new file mode 100644
index 0000000000..a89f14322b
--- /dev/null
+++ b/lib/core/form/models/form-rules.model.spec.ts
@@ -0,0 +1,93 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { setupTestBed } from '../../testing/setup-test-bed';
+import { FormBaseModule } from '../form-base.module';
+import { CoreTestingModule } from '../../testing';
+import { TranslateModule } from '@ngx-translate/core';
+import { ByPassFormRuleManager, FormRulesManager, formRulesManagerFactory, FORM_RULES_MANAGER } from '../models/form-rules.model';
+import { Injector } from '@angular/core';
+import { TestBed } from '@angular/core/testing';
+
+class CustomRuleManager extends FormRulesManager {
+ protected getRules() {
+ return null;
+ }
+ protected handleRuleEvent(): void {
+ return;
+ }
+
+}
+
+describe('Form Rules', () => {
+
+ let injector: Injector;
+ const customRuleManager = new CustomRuleManager(null);
+
+ describe('Injection token provided', () => {
+ setupTestBed({
+ imports: [
+ TranslateModule.forRoot(),
+ CoreTestingModule,
+ FormBaseModule
+ ],
+ providers: [
+ {
+ provide: FORM_RULES_MANAGER,
+ useValue: customRuleManager
+ }
+ ]
+ });
+
+ beforeEach(() => {
+ injector = TestBed.inject(Injector);
+ });
+
+ it('factory function should not return bypass service', () => {
+ spyOn(customRuleManager, 'destroy');
+ spyOn(customRuleManager, 'initialize');
+ const rulesManager = formRulesManagerFactory(injector);
+
+ expect(rulesManager instanceof CustomRuleManager).toBeTruthy();
+
+ rulesManager.destroy();
+ expect(customRuleManager.destroy).toHaveBeenCalled();
+ rulesManager.initialize(null);
+ expect(customRuleManager.initialize).toHaveBeenCalled();
+ });
+ });
+
+ describe('Injection token not provided', () => {
+ setupTestBed({
+ imports: [
+ TranslateModule.forRoot(),
+ CoreTestingModule,
+ FormBaseModule
+ ]
+ });
+
+ beforeEach(() => {
+ injector = TestBed.inject(Injector);
+ });
+
+ it('factory function should return bypass service', () => {
+ const rulesManager = formRulesManagerFactory(injector);
+
+ expect(rulesManager instanceof ByPassFormRuleManager).toBeTruthy();
+ });
+ });
+});
diff --git a/lib/core/form/models/form-rules.model.ts b/lib/core/form/models/form-rules.model.ts
new file mode 100644
index 0000000000..32f652405d
--- /dev/null
+++ b/lib/core/form/models/form-rules.model.ts
@@ -0,0 +1,81 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { InjectionToken, Injector } from '@angular/core';
+import { Subject } from 'rxjs';
+import { filter, takeUntil } from 'rxjs/operators';
+import { FormRulesEvent } from '../events/form-rules.event';
+import { FormModel, FormService } from '../public-api';
+
+export const FORM_RULES_MANAGER = new InjectionToken>('form.rule.manager');
+
+export function formRulesManagerFactory(injector: Injector): FormRulesManager {
+ try {
+ return injector.get(FORM_RULES_MANAGER);
+ } catch {
+ return new ByPassFormRuleManager(null);
+ }
+}
+
+export abstract class FormRulesManager {
+ constructor(private formService: FormService) { }
+
+ protected formModel: FormModel;
+ private onDestroy$ = new Subject();
+ private initialized = false;
+
+ initialize(formModel: FormModel) {
+ if (this.initialized) {
+ this.destroy();
+ this.onDestroy$ = new Subject();
+ }
+
+ this.formModel = formModel;
+ const rules = this.getRules();
+
+ if (!!rules) {
+ this.formService.formRulesEvent
+ .pipe(
+ filter(event => !!event.form.id && event.form.id === formModel?.id),
+ takeUntil(this.onDestroy$)
+ ).subscribe(event => {
+ this.handleRuleEvent(event, rules);
+ });
+ }
+
+ this.initialized = true;
+ }
+
+ protected abstract getRules(): T;
+ protected abstract handleRuleEvent(event: FormRulesEvent, rules: T): void;
+
+ destroy() {
+ this.onDestroy$.next(true);
+ this.onDestroy$.complete();
+ }
+}
+
+export class ByPassFormRuleManager extends FormRulesManager {
+
+ protected getRules(): T {
+ return null;
+ }
+
+ protected handleRuleEvent(): void {
+ return;
+ }
+}
diff --git a/lib/core/form/public-api.ts b/lib/core/form/public-api.ts
index 39fd7dadb1..4f67b97067 100644
--- a/lib/core/form/public-api.ts
+++ b/lib/core/form/public-api.ts
@@ -37,3 +37,5 @@ export * from './services/widget-visibility.service';
export * from './events/index';
export * from './form-base.module';
+
+export * from './models/form-rules.model';
diff --git a/lib/core/form/services/form.service.spec.ts b/lib/core/form/services/form.service.spec.ts
index 22619ce32b..0998eb32f8 100644
--- a/lib/core/form/services/form.service.spec.ts
+++ b/lib/core/form/services/form.service.spec.ts
@@ -21,6 +21,9 @@ import { FormService } from './form.service';
import { setupTestBed } from '../../testing/setup-test-bed';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { TranslateModule } from '@ngx-translate/core';
+import { FormEvent, ValidateDynamicTableRowEvent, ValidateFormEvent, ValidateFormFieldEvent } from '../events';
+import { take } from 'rxjs/operators';
+import { FormModel } from '../components/widgets/core/form.model';
declare let jasmine: any;
@@ -88,7 +91,7 @@ describe('Form service', () => {
it('should fetch and parse process definitions', (done) => {
service.getProcessDefinitions().subscribe(() => {
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('/process-definitions')).toBeTruthy();
- expect( [ { id: '1' }, { id: '2' } ]).toEqual(JSON.parse(jasmine.Ajax.requests.mostRecent().response).data);
+ expect([{ id: '1' }, { id: '2' }]).toEqual(JSON.parse(jasmine.Ajax.requests.mostRecent().response).data);
done();
});
@@ -102,7 +105,7 @@ describe('Form service', () => {
it('should fetch and parse tasks', (done) => {
service.getTasks().subscribe(() => {
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('/tasks/query')).toBeTruthy();
- expect( [ { id: '1' }, { id: '2' } ]).toEqual(JSON.parse(jasmine.Ajax.requests.mostRecent().response).data);
+ expect([{ id: '1' }, { id: '2' }]).toEqual(JSON.parse(jasmine.Ajax.requests.mostRecent().response).data);
done();
});
@@ -408,5 +411,69 @@ describe('Form service', () => {
done();
});
});
- });
+ });
+
+ describe('Form rules', () => {
+ const event = new FormEvent('mock');
+
+ it('should emit the formLoaded in the formRulesEvent observable', async(done) => {
+ service.formRulesEvent.pipe(take(1)).subscribe(formRuleEvent => {
+ expect(formRuleEvent.event).toBeFalsy();
+ expect(formRuleEvent.field).toBeFalsy();
+ expect(formRuleEvent.form).toEqual('mock');
+ expect(formRuleEvent.type).toEqual('formLoaded');
+ done();
+ });
+
+ service.formLoaded.next(event);
+ });
+
+ it('should emit the formDataRefreshed in the formRulesEvent observable', async(done) => {
+ service.formRulesEvent.pipe(take(1)).subscribe(formRuleEvent => {
+ expect(formRuleEvent.event).toBeFalsy();
+ expect(formRuleEvent.field).toBeFalsy();
+ expect(formRuleEvent.form).toEqual('mock');
+ expect(formRuleEvent.type).toEqual('formDataRefreshed');
+ done();
+ });
+
+ service.formDataRefreshed.next(event);
+ });
+
+ it('should emit the formValidated in the formRulesEvent observable', async(done) => {
+ service.formRulesEvent.pipe(take(1)).subscribe(formRuleEvent => {
+ expect(formRuleEvent.event).toBeFalsy();
+ expect(formRuleEvent.field).toBeFalsy();
+ expect(formRuleEvent.form).toEqual('mock');
+ expect(formRuleEvent.type).toEqual('formValidated');
+ done();
+ });
+
+ service.validateForm.next(new ValidateFormEvent('mock'));
+ });
+
+ it('should emit the fieldValidated in the formRulesEvent observable', async(done) => {
+ service.formRulesEvent.pipe(take(1)).subscribe(formRuleEvent => {
+ expect(formRuleEvent.event).toBeFalsy();
+ expect(formRuleEvent.field).toBeFalsy();
+ expect(formRuleEvent.form).toEqual('mock');
+ expect(formRuleEvent.type).toEqual('fieldValidated');
+ done();
+ });
+
+ service.validateFormField.next(new ValidateFormFieldEvent('mock', null));
+ });
+
+ it('should emit the fieldDynamicTableRowValidated in the formRulesEvent observable', async(done) => {
+ service.formRulesEvent.pipe(take(1)).subscribe(formRuleEvent => {
+ expect(formRuleEvent.event).toBeFalsy();
+ expect(formRuleEvent.field).toBeFalsy();
+ expect(formRuleEvent.form).toEqual('mock');
+ expect(formRuleEvent.type).toEqual('fieldDynamicTableRowValidated');
+ done();
+ });
+
+ service.validateDynamicTableRow.next(new ValidateDynamicTableRowEvent('mock' as unknown as FormModel, null, null, null));
+ });
+ });
});
diff --git a/lib/core/form/services/form.service.ts b/lib/core/form/services/form.service.ts
index 21be23cc9f..49fd879763 100644
--- a/lib/core/form/services/form.service.ts
+++ b/lib/core/form/services/form.service.ts
@@ -49,6 +49,7 @@ import { ValidateFormEvent } from '../events/validate-form.event';
import { ValidateFormFieldEvent } from '../events/validate-form-field.event';
import { ValidateDynamicTableRowEvent } from '../events/validate-dynamic-table-row.event';
import { FormValidationService } from './form-validation-service.interface';
+import { FormRulesEvent } from '../events/form-rules.event';
@Injectable({
providedIn: 'root'
@@ -130,9 +131,17 @@ export class FormService implements FormValidationService {
updateFormValuesRequested = new Subject();
+ formRulesEvent = new Subject();
+
constructor(private ecmModelService: EcmModelService,
private apiService: AlfrescoApiService,
protected logService: LogService) {
+
+ this.formLoaded.subscribe(event => this.formRulesEvent.next(new FormRulesEvent('formLoaded', event)));
+ this.formDataRefreshed.subscribe(event => this.formRulesEvent.next(new FormRulesEvent('formDataRefreshed', event)));
+ this.validateForm.subscribe(event => this.formRulesEvent.next(new FormRulesEvent('formValidated', event)));
+ this.validateFormField.subscribe(event => this.formRulesEvent.next(new FormRulesEvent('fieldValidated', event)));
+ this.validateDynamicTableRow.subscribe(event => this.formRulesEvent.next(new FormRulesEvent('fieldDynamicTableRowValidated', event)));
}
/**
diff --git a/lib/process-services-cloud/src/lib/form/mocks/cloud-form.mock.ts b/lib/process-services-cloud/src/lib/form/mocks/cloud-form.mock.ts
index 011325d895..4c2525efed 100644
--- a/lib/process-services-cloud/src/lib/form/mocks/cloud-form.mock.ts
+++ b/lib/process-services-cloud/src/lib/form/mocks/cloud-form.mock.ts
@@ -649,6 +649,7 @@ export const cloudFormMock = {
metadata: {},
variables: [
{
+ id: 'FormVarStrId',
name: 'FormVarStr',
type: 'string',
value: ''
diff --git a/lib/process-services/src/lib/form/form.component.visibility.spec.ts b/lib/process-services/src/lib/form/form.component.visibility.spec.ts
index 0fdef59724..ff31c4fe99 100644
--- a/lib/process-services/src/lib/form/form.component.visibility.spec.ts
+++ b/lib/process-services/src/lib/form/form.component.visibility.spec.ts
@@ -158,12 +158,12 @@ describe('FormComponent UI and visibility', () => {
fixture.detectChanges();
const firstEl = fixture.debugElement.query(By.css('#field-country-container'));
- expect(firstEl.nativeElement.hidden).toBeTruthy();
+ expect(firstEl.nativeElement.style.visibility).toBe('hidden');
const secondEl = fixture.debugElement.query(By.css('#name'));
expect(secondEl).not.toBeNull();
expect(secondEl).toBeDefined();
- expect(fixture.nativeElement.querySelector('#field-name-container').hidden).toBeFalsy();
+ expect(fixture.nativeElement.querySelector('#field-name-container').style.visibility).not.toBe('hidden');
});
it('should hide the field based on the previous one', () => {
@@ -177,10 +177,10 @@ describe('FormComponent UI and visibility', () => {
const firstEl = fixture.debugElement.query(By.css('#name'));
expect(firstEl).not.toBeNull();
expect(firstEl).toBeDefined();
- expect(fixture.nativeElement.querySelector('#field-name-container').hidden).toBeFalsy();
+ expect(fixture.nativeElement.querySelector('#field-name-container').style.visibility).not.toBe('hidden');
const secondEl = fixture.debugElement.query(By.css('#field-country-container'));
- expect(secondEl.nativeElement.hidden).toBeTruthy();
+ expect(secondEl.nativeElement.style.visibility).toBe('hidden');
});
it('should show the hidden field when the visibility condition change to true', () => {
@@ -192,10 +192,10 @@ describe('FormComponent UI and visibility', () => {
fixture.detectChanges();
let firstEl = fixture.debugElement.query(By.css('#field-country-container'));
- expect(firstEl.nativeElement.hidden).toBeTruthy();
+ expect(firstEl.nativeElement.style.visibility).toBe('hidden');
const secondEl = fixture.debugElement.query(By.css('#field-name-container'));
- expect(secondEl.nativeElement.hidden).toBeFalsy();
+ expect(secondEl.nativeElement.style.visibility).not.toBe('hidden');
const inputElement = fixture.nativeElement.querySelector('#name');
inputElement.value = 'italy';
@@ -203,7 +203,7 @@ describe('FormComponent UI and visibility', () => {
fixture.detectChanges();
firstEl = fixture.debugElement.query(By.css('#field-country-container'));
- expect(firstEl.nativeElement.hidden).toBeFalsy();
+ expect(firstEl.nativeElement.style.visibility).not.toBe('hidden');
});
});
diff --git a/lib/process-services/src/lib/task-list/components/task-form/task-form.component.spec.ts b/lib/process-services/src/lib/task-list/components/task-form/task-form.component.spec.ts
index f9d5db0928..7395753b85 100644
--- a/lib/process-services/src/lib/task-list/components/task-form/task-form.component.spec.ts
+++ b/lib/process-services/src/lib/task-list/components/task-form/task-form.component.spec.ts
@@ -513,9 +513,9 @@ describe('TaskFormComponent', () => {
fixture.detectChanges();
await fixture.whenStable();
const inputThreeContainer = fixture.nativeElement.querySelector('#field-text3-container');
- expect(inputThreeContainer.hidden).toBe(true);
+ expect(inputThreeContainer.style.visibility).toBe('hidden');
const completeOutcomeButton: HTMLButtonElement = fixture.nativeElement.querySelector('#adf-form-complete');
- expect(completeOutcomeButton.hidden).toBe(false);
+ expect(completeOutcomeButton.style.visibility).not.toBe('hidden');
completeOutcomeButton.click();
fixture.detectChanges();
});