diff --git a/lib/core/src/lib/form/components/form-field/form-field.component.html b/lib/core/src/lib/form/components/form-field/form-field.component.html
index 9a3a12f5ae..cf414fbc0d 100644
--- a/lib/core/src/lib/form/components/form-field/form-field.component.html
+++ b/lib/core/src/lib/form/components/form-field/form-field.component.html
@@ -1,6 +1,5 @@
{
fixture.detectChanges();
const styles = testingUtils.getByCSS('#field-FAKE-TXT-WIDGET-container').styles;
- expect(styles.visibility).toEqual('hidden');
expect(styles.display).toEqual('none');
});
@@ -135,7 +134,6 @@ describe('FormFieldComponent', () => {
fixture.detectChanges();
const styles = testingUtils.getByCSS('#field-FAKE-TXT-WIDGET-container').styles;
- expect(styles.visibility).toEqual('visible');
expect(styles.display).toEqual('block');
});
@@ -147,13 +145,14 @@ describe('FormFieldComponent', () => {
component.field = field;
fixture.detectChanges();
+
let styles = testingUtils.getByCSS('#field-FAKE-TXT-WIDGET-container').styles;
- expect(styles.visibility).toEqual('visible');
expect(styles.display).toEqual('block');
+
component.field.isVisible = false;
fixture.detectChanges();
+
styles = testingUtils.getByCSS('#field-FAKE-TXT-WIDGET-container').styles;
- expect(styles.visibility).toEqual('hidden');
expect(styles.display).toEqual('none');
});
diff --git a/lib/core/src/lib/form/components/form-renderer.component.html b/lib/core/src/lib/form/components/form-renderer.component.html
index 18f65a016b..19d2918172 100644
--- a/lib/core/src/lib/form/components/form-renderer.component.html
+++ b/lib/core/src/lib/form/components/form-renderer.component.html
@@ -38,15 +38,17 @@
-
+ [style.width.%]="getColumnWidth(currentRootElement)">
+
- to be implemented
+
-
+
-
+
diff --git a/lib/core/src/lib/form/components/form-renderer.component.scss b/lib/core/src/lib/form/components/form-renderer.component.scss
index 24d18d0b12..0234f31560 100644
--- a/lib/core/src/lib/form/components/form-renderer.component.scss
+++ b/lib/core/src/lib/form/components/form-renderer.component.scss
@@ -14,39 +14,37 @@
}
.adf-container-widget {
- .adf-grid-list-column-view {
- @include layout-bp(lt-md) {
- display: flow;
- }
-
- display: flex;
- align-items: flex-start;
- margin-right: -1%;
- }
-
- .adf-grid-list-single-column {
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- flex: 1 1 auto;
- }
-
- .adf-grid-list-column-view-item {
- width: 100%;
- flex-grow: 1;
- box-sizing: border-box;
- padding-left: 1%;
- padding-right: 1%;
- }
-
.adf-grid-list {
display: grid;
- }
- .adf-grid-list-item {
- box-sizing: border-box;
- padding-left: 3px;
- padding-right: 3px;
+ &-column-view {
+ @include layout-bp(lt-md) {
+ display: flow;
+ }
+
+ display: flex;
+ margin-right: -1%;
+
+ &-item {
+ width: 100%;
+ flex-grow: 1;
+ box-sizing: border-box;
+ padding-left: 1%;
+ padding-right: 1%;
+ }
+ }
+
+ &-single-column {
+ display: flex;
+ flex-direction: column;
+ flex: 1 1 auto;
+ }
+
+ &-item {
+ box-sizing: border-box;
+ padding-left: 3px;
+ padding-right: 3px;
+ }
}
@include layout-bp(lt-md) {
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 528dacd0b7..5ae5f4cef5 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
@@ -37,6 +37,7 @@ import {
formNumberTextJson,
formNumberWidgetVisibility,
formRequiredNumberWidget,
+ mockSectionVisibilityForm,
multilineWidgetFormVisibilityMock,
numberMinMaxForm,
numberNotRequiredForm,
@@ -44,22 +45,22 @@ import {
radioWidgetVisibilityForm,
textWidgetVisibility
} from './mock/form-renderer.component.mock';
-import { TextWidgetComponent } from './widgets';
+import { FormModel, TextWidgetComponent } from './widgets';
const typeIntoInput = (testingUtils: UnitTestingUtils, selector: string, message: string) => {
testingUtils.fillInputByCSS(selector, message);
};
-const expectElementToBeHidden = (testingUtils: UnitTestingUtils, selector: string): void => {
- const targetElement = testingUtils.getByCSS(selector).nativeElement;
+const expectElementToBeHidden = (testingUtils: UnitTestingUtils, fieldId: string): void => {
+ const targetElement = testingUtils.getByCSS(`#field-${fieldId}-container`).nativeElement;
expect(targetElement).toBeTruthy();
- expect(targetElement.style.visibility).toBe('hidden', `${targetElement.id} should be hidden but it is not`);
+ expect(targetElement.style.display).toBe('none', `${targetElement.id} should be hidden but it is not`);
};
-const expectElementToBeVisible = (testingUtils: UnitTestingUtils, selector: string): void => {
- const targetElement = testingUtils.getByCSS(selector).nativeElement;
+const expectElementToBeVisible = (testingUtils: UnitTestingUtils, fieldId: string, display: string = 'block'): void => {
+ const targetElement = testingUtils.getByCSS(`#field-${fieldId}-container`).nativeElement;
expect(targetElement).toBeTruthy();
- expect(targetElement.style.visibility).not.toBe('hidden', `${targetElement.id} should be visibile but it is not`);
+ expect(targetElement.style.display).toBe(display, `${targetElement.id} should be visible but it is not`);
};
const expectInputElementValueIs = (testingUtils: UnitTestingUtils, selector: string, value: string): void => {
@@ -108,13 +109,13 @@ describe('Form Renderer Component', () => {
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-Text0pqd1u-container');
+ expectElementToBeHidden(testingUtils, 'Text0pqd1u');
testingUtils.fillInputByCSS('#Date0hwq20', '2019-11-19');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Text0pqd1u-container');
+ expectElementToBeVisible(testingUtils, 'Text0pqd1u');
});
it('Should not be able to see a widget when the visibility condition refers to another fields with specific date', async () => {
@@ -122,14 +123,14 @@ describe('Form Renderer Component', () => {
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Text0uyqd3-container');
+ expectElementToBeVisible(testingUtils, 'Text0uyqd3');
testingUtils.fillInputByCSS('#Date0hwq20', '2019-11-19');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-Text0uyqd3-container');
+ expectElementToBeHidden(testingUtils, 'Text0uyqd3');
});
it('[C310336] - Should be able to set visibility conditions for Date widget', async () => {
@@ -137,14 +138,14 @@ describe('Form Renderer Component', () => {
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Text5asd0a-container');
- expectElementToBeHidden(testingUtils, '#field-Date8wbe3d-container');
+ expectElementToBeVisible(testingUtils, 'Text5asd0a');
+ expectElementToBeHidden(testingUtils, 'Date8wbe3d');
typeIntoInput(testingUtils, '#Text5asd0a', 'Date');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Date8wbe3d-container');
+ expectElementToBeVisible(testingUtils, 'Date8wbe3d');
});
});
@@ -154,12 +155,12 @@ describe('Form Renderer Component', () => {
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-Displayvalue0g6092-container');
+ expectElementToBeHidden(testingUtils, 'Displayvalue0g6092');
typeIntoInput(testingUtils, '#Text0bq3ar', 'DisplayValue');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Displayvalue0g6092-container');
+ expectElementToBeVisible(testingUtils, 'Displayvalue0g6092');
expectInputElementValueIs(testingUtils, '#Displayvalue0g6092', 'No field selected');
});
@@ -167,82 +168,82 @@ describe('Form Renderer Component', () => {
formRendererComponent.formDefinition = formService.parseForm(formDisplayValueForm.formRepresentation.formDefinition);
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-DisplayValueOne-container');
+ expectElementToBeHidden(testingUtils, 'DisplayValueOne');
typeIntoInput(testingUtils, '#Text0howrc', 'aaa');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-DisplayValueOne-container');
+ expectElementToBeVisible(testingUtils, 'DisplayValueOne');
expectInputElementValueIs(testingUtils, '#DisplayValueOne', 'No field selected');
typeIntoInput(testingUtils, '#Text0howrc', 'aaab');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-DisplayValueOne-container');
+ expectElementToBeHidden(testingUtils, 'DisplayValueOne');
});
it('[C309864] - Should be able to see Display value widget when visibility condition refers to another field and form variable', async () => {
formRendererComponent.formDefinition = formService.parseForm(formDisplayValueForm.formRepresentation.formDefinition);
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-DisplayValueVariableField-container');
+ expectElementToBeHidden(testingUtils, 'DisplayValueVariableField');
typeIntoInput(testingUtils, '#TextOne', 'aaa');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-DisplayValueVariableField-container');
+ expectElementToBeVisible(testingUtils, 'DisplayValueVariableField');
expectInputElementValueIs(testingUtils, '#DisplayValueVariableField', 'No field selected');
typeIntoInput(testingUtils, '#TextOne', 'aaab');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-DisplayValueVariableField-container');
+ expectElementToBeHidden(testingUtils, 'DisplayValueVariableField');
});
it('[C309865] - Should be able to see Display value widget when has multiple visibility conditions and next condition operators', async () => {
formRendererComponent.formDefinition = formService.parseForm(formDisplayValueCombinedVisibility.formRepresentation.formDefinition);
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#Text0bq3ar');
- expectElementToBeVisible(testingUtils, '#TextTwo');
- expectElementToBeHidden(testingUtils, '#field-Displayvalue0g6092-container');
+ expectElementToBeVisible(testingUtils, 'Text0bq3ar');
+ expectElementToBeVisible(testingUtils, 'TextTwo');
+ expectElementToBeHidden(testingUtils, 'Displayvalue0g6092');
typeIntoInput(testingUtils, '#Text0bq3ar', 'aaa');
fixture.detectChanges();
await fixture.whenStable();
typeIntoInput(testingUtils, '#Text0bq3ar', 'aaa');
expectInputElementValueIs(testingUtils, '#TextTwo', '');
- expectElementToBeVisible(testingUtils, '#field-Displayvalue0g6092-container');
+ expectElementToBeVisible(testingUtils, 'Displayvalue0g6092');
typeIntoInput(testingUtils, '#Text0bq3ar', 'bbb');
fixture.detectChanges();
await fixture.whenStable();
typeIntoInput(testingUtils, '#Text0bq3ar', 'bbb');
expectInputElementValueIs(testingUtils, '#TextTwo', '');
- expectElementToBeHidden(testingUtils, '#field-Displayvalue0g6092-container');
+ expectElementToBeHidden(testingUtils, 'Displayvalue0g6092');
typeIntoInput(testingUtils, '#TextTwo', 'aaa');
fixture.detectChanges();
await fixture.whenStable();
typeIntoInput(testingUtils, '#Text0bq3ar', 'bbb');
expectInputElementValueIs(testingUtils, '#TextTwo', 'aaa');
- expectElementToBeHidden(testingUtils, '#field-Displayvalue0g6092-container');
+ expectElementToBeHidden(testingUtils, 'Displayvalue0g6092');
typeIntoInput(testingUtils, '#Text0bq3ar', 'aaa');
fixture.detectChanges();
await fixture.whenStable();
typeIntoInput(testingUtils, '#Text0bq3ar', 'aaa');
expectInputElementValueIs(testingUtils, '#TextTwo', 'aaa');
- expectElementToBeHidden(testingUtils, '#field-Displayvalue0g6092-container');
+ expectElementToBeHidden(testingUtils, 'Displayvalue0g6092');
typeIntoInput(testingUtils, '#TextTwo', 'bbb');
fixture.detectChanges();
await fixture.whenStable();
typeIntoInput(testingUtils, '#Text0bq3ar', 'aaa');
expectInputElementValueIs(testingUtils, '#TextTwo', 'bbb');
- expectElementToBeVisible(testingUtils, '#field-Displayvalue0g6092-container');
+ expectElementToBeVisible(testingUtils, 'Displayvalue0g6092');
});
});
@@ -252,24 +253,24 @@ describe('Form Renderer Component', () => {
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#Number1');
- expectElementToBeHidden(testingUtils, '#field-Number2-container');
+ expectElementToBeVisible(testingUtils, 'Number1');
+ expectElementToBeHidden(testingUtils, 'Number2');
expect(formRendererComponent.formDefinition.isValid).toBe(true, 'Form should be valid by default');
typeIntoInput(testingUtils, '#Number1', '5');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#Number1');
- expectElementToBeVisible(testingUtils, '#field-Number2-container');
+ expectElementToBeVisible(testingUtils, 'Number1');
+ expectElementToBeVisible(testingUtils, 'Number2');
expect(formRendererComponent.formDefinition.isValid).toBe(true, 'Form should be valid with a valid value');
typeIntoInput(testingUtils, '#Number1', 'az');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#Number1');
- expectElementToBeHidden(testingUtils, '#field-Number2-container');
+ expectElementToBeVisible(testingUtils, 'Number1');
+ expectElementToBeHidden(testingUtils, 'Number2');
expect(formRendererComponent.formDefinition.isValid).toBe(false, 'Form should be invalid with an invalid value');
});
@@ -278,18 +279,18 @@ describe('Form Renderer Component', () => {
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#Text');
- expectElementToBeHidden(testingUtils, '#field-NumberFieldValue-container');
+ expectElementToBeVisible(testingUtils, 'Text');
+ expectElementToBeHidden(testingUtils, 'NumberFieldValue');
typeIntoInput(testingUtils, '#Text', 'aaa');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-NumberFieldValue-container');
+ expectElementToBeVisible(testingUtils, 'NumberFieldValue');
typeIntoInput(testingUtils, '#Text', 'bbb');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-NumberFieldValue-container');
+ expectElementToBeHidden(testingUtils, 'NumberFieldValue');
});
it('[C315170] - Should be able to complete a task with a form with required number widgets', async () => {
@@ -297,18 +298,18 @@ describe('Form Renderer Component', () => {
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-Number2-container');
- expectElementToBeVisible(testingUtils, '#Number1');
+ expectElementToBeHidden(testingUtils, 'Number2');
+ expectElementToBeVisible(testingUtils, 'Number1');
typeIntoInput(testingUtils, '#Number1', '5');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Number2-container');
+ expectElementToBeVisible(testingUtils, 'Number2');
typeIntoInput(testingUtils, '#Number1', '123');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-Number2-container');
+ expectElementToBeHidden(testingUtils, 'Number2');
const errorWidgetText = testingUtils.getByCSS('#field-Number1-container error-widget .adf-error-text').nativeElement;
expect(errorWidgetText.textContent).toBe(`FORM.FIELD.VALIDATOR.NOT_GREATER_THAN`);
expect(formRendererComponent.formDefinition.isValid).toBe(false, 'Form should not be valid without mandatory field');
@@ -318,8 +319,8 @@ describe('Form Renderer Component', () => {
formRendererComponent.formDefinition = formService.parseForm(formNumberTextJson.formRepresentation.formDefinition);
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#NumberReq');
- expectElementToBeVisible(testingUtils, '#NumberNotReq');
+ expectElementToBeVisible(testingUtils, 'NumberReq');
+ expectElementToBeVisible(testingUtils, 'NumberNotReq');
expect(formRendererComponent.formDefinition.isValid).toBe(false, 'Form should be invalid with an empty required value');
typeIntoInput(testingUtils, '#NumberNotReq', '5');
@@ -338,7 +339,13 @@ describe('Form Renderer Component', () => {
formRendererComponent.formDefinition = formService.parseForm(colspanForm.formRepresentation.formDefinition, null, false, true);
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-2bc275fb-e113-4d7d-885f-6e74a7332d40-container div.adf-grid-list');
+
+ const numbersContainerGridElement = testingUtils.getByCSS(
+ `#field-2bc275fb-e113-4d7d-885f-6e74a7332d40-container div.adf-grid-list`
+ ).nativeElement;
+ expect(numbersContainerGridElement).toBeTruthy();
+ expect(numbersContainerGridElement.style.display).not.toBe('hidden');
+
const sectionGridElement: HTMLElement[] = testingUtils
.getAllByCSS('#field-2bc275fb-e113-4d7d-885f-6e74a7332d40-container div .adf-grid-list-item')
.map((element) => element.nativeElement);
@@ -356,7 +363,13 @@ describe('Form Renderer Component', () => {
formRendererComponent.formDefinition = formService.parseForm(colspanForm.formRepresentation.formDefinition, null, false, false);
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-2bc275fb-e113-4d7d-885f-6e74a7332d40-container section.adf-grid-list-column-view');
+
+ const numbersContainerElement = testingUtils.getByCSS(
+ `#field-2bc275fb-e113-4d7d-885f-6e74a7332d40-container section.adf-grid-list-column-view`
+ ).nativeElement;
+ expect(numbersContainerElement).toBeTruthy();
+ expect(numbersContainerElement.style.display).not.toBe('hidden');
+
const sectionGridElement = testingUtils
.getAllByCSS('#field-2bc275fb-e113-4d-7d-885f-6e74a7332d40-container section .adf-grid-list-single-column')
.map((element) => element.nativeElement);
@@ -376,7 +389,10 @@ describe('Form Renderer Component', () => {
const twoSpanTextWidgetContainerId = '#field-1ff21afc-7df4-4607-8363-1dc8576e1c8e-container';
const oneSpanTextWidgetContainerId = '#field-f4285ad-g123-1a73-521d-7nm4a7231aul0-container';
- expectElementToBeVisible(testingUtils, `${oneSpanTextWidgetContainerId} section.adf-grid-list-column-view`);
+ const oneSpanTextWidgetElement = testingUtils.getByCSS(`${oneSpanTextWidgetContainerId} section.adf-grid-list-column-view`).nativeElement;
+ expect(oneSpanTextWidgetElement).toBeTruthy();
+ expect(oneSpanTextWidgetElement.style.display).not.toBe('hidden');
+
const sectionGridElement = testingUtils
.getAllByCSS(`${oneSpanTextWidgetContainerId} section .adf-grid-list-single-column`)
.map((element) => element.nativeElement);
@@ -394,7 +410,7 @@ describe('Form Renderer Component', () => {
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#Number0x8cbv');
+ expectElementToBeVisible(testingUtils, 'Number0x8cbv');
expectElementToBeValid(testingUtils, 'Number0x8cbv');
testingUtils.blurByCSS('#Number0x8cbv');
@@ -434,7 +450,7 @@ describe('Form Renderer Component', () => {
formRendererComponent.formDefinition = formService.parseForm(numberMinMaxForm.formRepresentation.formDefinition);
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#Number0him2z');
+ expectElementToBeVisible(testingUtils, 'Number0him2z');
expectElementToBeValid(testingUtils, 'Number0him2z');
testingUtils.blurByCSS('#Number0him2z');
@@ -475,17 +491,17 @@ describe('Form Renderer Component', () => {
await fixture.whenStable();
const inputText = testingUtils.getByCSS('#Text').nativeElement;
expect(inputText).not.toBeNull();
- expectElementToBeHidden(testingUtils, '#field-NumberFieldValue-container');
+ expectElementToBeHidden(testingUtils, 'NumberFieldValue');
typeIntoInput(testingUtils, '#Text', 'aaa');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-NumberFieldValue-container');
+ expectElementToBeVisible(testingUtils, 'NumberFieldValue');
typeIntoInput(testingUtils, '#Text', 'bbb');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-NumberFieldValue-container');
+ expectElementToBeHidden(testingUtils, 'NumberFieldValue');
});
it('[C309665] - Should be able to see Number widget when visibility condition refers to another field and form variable', async () => {
@@ -494,39 +510,39 @@ describe('Form Renderer Component', () => {
await fixture.whenStable();
const inputText = testingUtils.getByCSS('#Text').nativeElement;
expect(inputText).not.toBeNull();
- expectElementToBeHidden(testingUtils, '#field-NumberFieldVariable-container');
+ expectElementToBeHidden(testingUtils, 'NumberFieldVariable');
typeIntoInput(testingUtils, '#Text', 'aaa');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-NumberFieldVariable-container');
+ expectElementToBeVisible(testingUtils, 'NumberFieldVariable');
typeIntoInput(testingUtils, '#Text', 'bbb');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-NumberFieldVariable-container');
+ expectElementToBeHidden(testingUtils, 'NumberFieldVariable');
});
it('[C309666] - Should be able to see Number widget when has multiple visibility conditions and next condition operators', async () => {
formRendererComponent.formDefinition = formService.parseForm(numberWidgetVisibilityForm.formRepresentation.formDefinition);
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-Number0wxaur-container');
+ expectElementToBeHidden(testingUtils, 'Number0wxaur');
typeIntoInput(testingUtils, '#Text0hs0gt', 'aaa');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Number0wxaur-container');
+ expectElementToBeVisible(testingUtils, 'Number0wxaur');
typeIntoInput(testingUtils, '#Text0hs0gt', 'bbb');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-Number0wxaur-container');
+ expectElementToBeHidden(testingUtils, 'Number0wxaur');
typeIntoInput(testingUtils, '#Text0cuqet', 'aaa');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-Number0wxaur-container');
+ expectElementToBeHidden(testingUtils, 'Number0wxaur');
expectInputElementValueIs(testingUtils, '#Text0hs0gt', 'bbb');
typeIntoInput(testingUtils, '#Text0hs0gt', 'aaa');
@@ -534,7 +550,7 @@ describe('Form Renderer Component', () => {
await fixture.whenStable();
expectInputElementValueIs(testingUtils, '#Text0hs0gt', 'aaa');
expectInputElementValueIs(testingUtils, '#Text0cuqet', 'aaa');
- expectElementToBeHidden(testingUtils, '#field-Number0wxaur-container');
+ expectElementToBeHidden(testingUtils, 'Number0wxaur');
});
});
@@ -543,26 +559,26 @@ describe('Form Renderer Component', () => {
formRendererComponent.formDefinition = formService.parseForm(textWidgetVisibility.formRepresentation.formDefinition);
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#textOne');
- expectElementToBeHidden(testingUtils, '#field-textThree-container');
- expectElementToBeHidden(testingUtils, '#field-textTwo-container');
- expectElementToBeVisible(testingUtils, '#field-textFour-container');
+ expectElementToBeVisible(testingUtils, 'textOne');
+ expectElementToBeHidden(testingUtils, 'textThree');
+ expectElementToBeHidden(testingUtils, 'textTwo');
+ expectElementToBeVisible(testingUtils, 'textFour');
typeIntoInput(testingUtils, '#textOne', 'Test');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-textOne-container');
- expectElementToBeVisible(testingUtils, '#field-textTwo-container');
- expectElementToBeVisible(testingUtils, '#field-textThree-container');
- expectElementToBeHidden(testingUtils, '#field-textFour-container');
+ expectElementToBeVisible(testingUtils, 'textOne');
+ expectElementToBeVisible(testingUtils, 'textTwo');
+ expectElementToBeVisible(testingUtils, 'textThree');
+ expectElementToBeHidden(testingUtils, 'textFour');
typeIntoInput(testingUtils, '#textTwo', 'Test');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-textOne-container');
- expectElementToBeVisible(testingUtils, '#field-textTwo-container');
- expectElementToBeVisible(testingUtils, '#field-textFour-container');
- expectElementToBeHidden(testingUtils, '#field-textThree-container');
+ expectElementToBeVisible(testingUtils, 'textOne');
+ expectElementToBeVisible(testingUtils, 'textTwo');
+ expectElementToBeVisible(testingUtils, 'textFour');
+ expectElementToBeHidden(testingUtils, 'textThree');
});
});
@@ -571,13 +587,13 @@ describe('Form Renderer Component', () => {
formRendererComponent.formDefinition = formService.parseForm(radioWidgetVisibilityForm.formRepresentation.formDefinition);
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Text0cee7g-container');
- expectElementToBeHidden(testingUtils, '#field-Radiobuttons03rkbo-container');
+ expectElementToBeVisible(testingUtils, 'Text0cee7g');
+ expectElementToBeHidden(testingUtils, 'Radiobuttons03rkbo');
typeIntoInput(testingUtils, '#Text0cee7g', 'Radio');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Radiobuttons03rkbo-container');
+ expectElementToBeVisible(testingUtils, 'Radiobuttons03rkbo');
});
});
@@ -587,8 +603,8 @@ describe('Form Renderer Component', () => {
formRendererComponent.formDefinition = formService.parseForm(customWidgetForm.formRepresentation.formDefinition);
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#Text0vdi18');
- expectElementToBeVisible(testingUtils, '#bananaforevah0k8gui');
+ expectElementToBeVisible(testingUtils, 'Text0vdi18');
+ expectElementToBeVisible(testingUtils, 'bananaforevah0k8gui');
});
it('Should be able to correctly use visibility in a custom process cloud widget ', async () => {
@@ -596,11 +612,11 @@ describe('Form Renderer Component', () => {
formRendererComponent.formDefinition = formService.parseForm(customWidgetFormWithVisibility.formRepresentation.formDefinition);
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-bananaforevah0k8gui-container');
+ expectElementToBeHidden(testingUtils, 'bananaforevah0k8gui');
typeIntoInput(testingUtils, '#Text0vdi18', 'no');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-bananaforevah0k8gui-container');
+ expectElementToBeVisible(testingUtils, 'bananaforevah0k8gui');
});
});
@@ -641,15 +657,15 @@ describe('Form Renderer Component', () => {
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Text0id3ic-container');
- expectElementToBeVisible(testingUtils, '#field-Number0yggl7-container');
- expectElementToBeHidden(testingUtils, '#field-Amount0kceqc-container');
+ expectElementToBeVisible(testingUtils, 'Text0id3ic');
+ expectElementToBeVisible(testingUtils, 'Number0yggl7');
+ expectElementToBeHidden(testingUtils, 'Amount0kceqc');
typeIntoInput(testingUtils, '#Text0id3ic', 'text1');
typeIntoInput(testingUtils, '#Number0yggl7', '77');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Amount0kceqc-container');
+ expectElementToBeVisible(testingUtils, 'Amount0kceqc');
});
});
@@ -659,19 +675,19 @@ describe('Form Renderer Component', () => {
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Checkbox0pr51m-container');
- expectElementToBeVisible(testingUtils, '#field-Checkbox0fp0zf-container');
- expectElementToBeHidden(testingUtils, '#field-Checkbox0lb7ze-container');
+ expectElementToBeVisible(testingUtils, 'Checkbox0pr51m');
+ expectElementToBeVisible(testingUtils, 'Checkbox0fp0zf');
+ expectElementToBeHidden(testingUtils, 'Checkbox0lb7ze');
testingUtils.clickByCSS('#Checkbox0pr51m-input');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-Checkbox0lb7ze-container');
+ expectElementToBeHidden(testingUtils, 'Checkbox0lb7ze');
testingUtils.clickByCSS('#Checkbox0fp0zf-input');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Checkbox0lb7ze-container');
+ expectElementToBeVisible(testingUtils, 'Checkbox0lb7ze');
});
});
@@ -681,18 +697,18 @@ describe('Form Renderer Component', () => {
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Text-container');
- expectElementToBeVisible(testingUtils, '#field-MultilineTextId-container');
+ expectElementToBeVisible(testingUtils, 'Text');
+ expectElementToBeVisible(testingUtils, 'MultilineTextId');
typeIntoInput(testingUtils, '#Text', 'textwrong');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-MultilineTextId-container');
+ expectElementToBeHidden(testingUtils, 'MultilineTextId');
typeIntoInput(testingUtils, '#Text', 'text');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-MultilineTextId-container');
+ expectElementToBeVisible(testingUtils, 'MultilineTextId');
});
});
@@ -702,18 +718,18 @@ describe('Form Renderer Component', () => {
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Text0tzu53-container');
- expectElementToBeHidden(testingUtils, '#field-Displaytext0q4w02-container');
+ expectElementToBeVisible(testingUtils, 'Text0tzu53');
+ expectElementToBeHidden(testingUtils, 'Displaytext0q4w02');
typeIntoInput(testingUtils, '#Text0tzu53', 'aaa-value');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Displaytext0q4w02-container');
+ expectElementToBeVisible(testingUtils, 'Displaytext0q4w02');
typeIntoInput(testingUtils, '#Text0tzu53', 'bbb');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-Displaytext0q4w02-container');
+ expectElementToBeHidden(testingUtils, 'Displaytext0q4w02');
});
it('[C309870] - Should be able to see Display text widget when visibility condition refers to another field and form variable', async () => {
@@ -721,18 +737,18 @@ describe('Form Renderer Component', () => {
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Text0tzu53-container');
- expectElementToBeHidden(testingUtils, '#field-Displaytext8bac2e-container');
+ expectElementToBeVisible(testingUtils, 'Text0tzu53');
+ expectElementToBeHidden(testingUtils, 'Displaytext8bac2e');
typeIntoInput(testingUtils, '#Text0tzu53', 'aaa-variable');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeVisible(testingUtils, '#field-Displaytext8bac2e-container');
+ expectElementToBeVisible(testingUtils, 'Displaytext8bac2e');
typeIntoInput(testingUtils, '#Text0tzu53', 'bbb');
fixture.detectChanges();
await fixture.whenStable();
- expectElementToBeHidden(testingUtils, '#field-Displaytext8bac2e-container');
+ expectElementToBeHidden(testingUtils, 'Displaytext8bac2e');
});
});
@@ -746,4 +762,33 @@ describe('Form Renderer Component', () => {
expect(decimalInputElement.value).toBeTruthy('10.12');
});
});
+
+ describe('Section', () => {
+ it('should be able to set visibility conditions for Section with fields', () => {
+ const formDefinition = new FormModel(mockSectionVisibilityForm);
+ const sectionIdSelector = '48e6bfed-b477-4641-86cb-bfa70229a31e';
+ const mockTextDisplaySectionId = 'Text0n9o62';
+ const mockTestDisplaySectionFieldId = 'Text0nu6os';
+ const mockSectionFieldId = 'Text0t23xu';
+
+ fixture.componentRef.setInput('formDefinition', formDefinition);
+ fixture.detectChanges();
+
+ expectElementToBeVisible(testingUtils, mockTestDisplaySectionFieldId);
+ expectElementToBeVisible(testingUtils, mockTextDisplaySectionId);
+
+ expectElementToBeHidden(testingUtils, sectionIdSelector);
+ expectElementToBeHidden(testingUtils, mockSectionFieldId);
+
+ typeIntoInput(testingUtils, `#${mockTextDisplaySectionId}`, 'section');
+ fixture.detectChanges();
+
+ expectElementToBeVisible(testingUtils, sectionIdSelector, 'flex');
+
+ typeIntoInput(testingUtils, `#${mockTestDisplaySectionFieldId}`, 'section text');
+ fixture.detectChanges();
+
+ expectElementToBeVisible(testingUtils, mockSectionFieldId);
+ });
+ });
});
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 68b525487c..de3797b466 100644
--- a/lib/core/src/lib/form/components/form-renderer.component.ts
+++ b/lib/core/src/lib/form/components/form-renderer.component.ts
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-import { JsonPipe, NgClass, NgForOf, NgIf, NgStyle, NgTemplateOutlet, UpperCasePipe } from '@angular/common';
+import { JsonPipe, NgClass, NgForOf, NgIf, NgStyle, NgTemplateOutlet } from '@angular/common';
import { Component, Inject, Injector, Input, OnDestroy, OnInit, Optional, ViewEncapsulation } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
@@ -28,8 +28,8 @@ import { FormService } from '../services/form.service';
import { FormFieldComponent } from './form-field/form-field.component';
import { FORM_FIELD_MODEL_RENDER_MIDDLEWARE, FormFieldModelRenderMiddleware } from './middlewares/middleware';
import { ContainerModel, FormFieldModel, FormModel, TabModel } from './widgets';
-import { FieldStylePipe } from '../pipes/field-style.pipe';
import { HeaderWidgetComponent } from './widgets/header/header.widget';
+import { FormSectionComponent } from './form-section/form-section.component';
@Component({
selector: 'adf-form-renderer',
@@ -56,10 +56,9 @@ import { HeaderWidgetComponent } from './widgets/header/header.widget';
MatSlideToggleModule,
FormsModule,
JsonPipe,
- UpperCasePipe,
- FieldStylePipe,
NgClass,
- HeaderWidgetComponent
+ HeaderWidgetComponent,
+ FormSectionComponent
],
encapsulation: ViewEncapsulation.None
})
@@ -154,9 +153,10 @@ export class FormRendererComponent
implements OnInit, OnDestroy {
* @param container container model
* @returns the column width for the given model
*/
- getColumnWith(container: ContainerModel): string {
- const colspan = container ? container.field.colspan : 1;
- return (100 / container.field.numberOfColumns) * colspan + '';
+ getColumnWidth(container: ContainerModel): string {
+ const { field } = container;
+ const colspan = field ? field.colspan : 1;
+ return (100 / field.numberOfColumns) * colspan + '';
}
private runMiddlewareServices(): void {
diff --git a/lib/core/src/lib/form/components/form-section/form-section.component.html b/lib/core/src/lib/form/components/form-section/form-section.component.html
new file mode 100644
index 0000000000..8d69084307
--- /dev/null
+++ b/lib/core/src/lib/form/components/form-section/form-section.component.html
@@ -0,0 +1,11 @@
+
diff --git a/lib/core/src/lib/form/components/form-section/form-section.component.scss b/lib/core/src/lib/form/components/form-section/form-section.component.scss
new file mode 100644
index 0000000000..8181567b2a
--- /dev/null
+++ b/lib/core/src/lib/form/components/form-section/form-section.component.scss
@@ -0,0 +1,18 @@
+.adf-grid-list {
+ &-section {
+ &-single-column {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: flex-start;
+ }
+
+ &-column-view-item {
+ width: 100%;
+ display: flex;
+ flex-grow: 1;
+ box-sizing: border-box;
+ padding-left: 1%;
+ padding-right: 1%;
+ }
+ }
+}
diff --git a/lib/core/src/lib/form/components/form-section/form-section.component.spec.ts b/lib/core/src/lib/form/components/form-section/form-section.component.spec.ts
new file mode 100644
index 0000000000..f7143fb6e6
--- /dev/null
+++ b/lib/core/src/lib/form/components/form-section/form-section.component.spec.ts
@@ -0,0 +1,62 @@
+/*!
+ * @license
+ * Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
+ *
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { CoreTestingModule, UnitTestingUtils } from '../../../testing';
+import { FormFieldModel, FormModel } from '../widgets';
+import { FormSectionComponent } from './form-section.component';
+import { mockSectionWithFields } from '../mock/form-renderer.component.mock';
+
+describe('FormSectionComponent', () => {
+ let fixture: ComponentFixture;
+ let component: FormSectionComponent;
+ let testingUtils: UnitTestingUtils;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [CoreTestingModule]
+ });
+ fixture = TestBed.createComponent(FormSectionComponent);
+ testingUtils = new UnitTestingUtils(fixture.debugElement);
+ component = fixture.componentInstance;
+ });
+
+ it('should calculate the correct width for section columns', () => {
+ const numberOfColumns = 3;
+ const columnField = { colspan: 2 } as FormFieldModel;
+
+ const width = component.getSectionColumnWidth(numberOfColumns, [columnField]);
+ expect(width).toBe('66.66666666666667');
+ });
+
+ it('should handle columns with no colspan defined', () => {
+ const numberOfColumns = 3;
+ const columnField = {} as FormFieldModel;
+
+ const width = component.getSectionColumnWidth(numberOfColumns, [columnField]);
+ expect(width).toBe('33.333333333333336');
+ });
+
+ it('should display fields inside section', () => {
+ const sectionField = new FormFieldModel(new FormModel(), mockSectionWithFields);
+ fixture.componentRef.setInput('field', sectionField);
+ fixture.detectChanges();
+
+ const sectionFields = testingUtils.getAllByCSS('.adf-grid-list-section-column-view-item adf-form-field');
+ expect(sectionFields.length).toBe(2);
+ });
+});
diff --git a/lib/core/src/lib/form/components/form-section/form-section.component.ts b/lib/core/src/lib/form/components/form-section/form-section.component.ts
new file mode 100644
index 0000000000..3652151a98
--- /dev/null
+++ b/lib/core/src/lib/form/components/form-section/form-section.component.ts
@@ -0,0 +1,49 @@
+/*!
+ * @license
+ * Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
+ *
+ * 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 { Component, inject, Input, OnInit, ViewEncapsulation } from '@angular/core';
+import { WidgetVisibilityService } from '../../services/widget-visibility.service';
+import { FormFieldModel } from '../widgets/core/form-field.model';
+import { FormFieldComponent } from '../form-field/form-field.component';
+import { NgFor } from '@angular/common';
+
+@Component({
+ selector: 'adf-form-section',
+ standalone: true,
+ templateUrl: './form-section.component.html',
+ encapsulation: ViewEncapsulation.None,
+ styleUrls: ['./form-section.component.scss'],
+ imports: [NgFor, FormFieldComponent]
+})
+export class FormSectionComponent implements OnInit {
+ @Input()
+ field: FormFieldModel = null;
+
+ private readonly visibilityService = inject(WidgetVisibilityService);
+
+ ngOnInit(): void {
+ this.visibilityService.refreshVisibility(this.field.form);
+ }
+
+ getSectionColumnWidth(numberOfColumns: number, columnFields: FormFieldModel[]): string {
+ const firstColumnFieldIndex = 0;
+ const defaultColspan = 1;
+ const fieldColspan = columnFields[firstColumnFieldIndex]?.colspan ?? defaultColspan;
+
+ return (100 / numberOfColumns) * fieldColspan + '';
+ }
+}
diff --git a/lib/core/src/lib/form/components/mock/form-renderer.component.mock.ts b/lib/core/src/lib/form/components/mock/form-renderer.component.mock.ts
index 05bd6a8168..fb22f95685 100644
--- a/lib/core/src/lib/form/components/mock/form-renderer.component.mock.ts
+++ b/lib/core/src/lib/form/components/mock/form-renderer.component.mock.ts
@@ -2135,3 +2135,213 @@ export const displayBigDecimalWidgetMock = {
}
}
};
+
+export const mockSectionWithFields = {
+ id: '51058d64-b36c-48f0-97a2-d9bd0398edab',
+ name: 'Section',
+ type: 'section',
+ numberOfColumns: 2,
+ fields: {
+ 1: [
+ {
+ id: 'Text07kgd8',
+ name: 'Text',
+ type: 'text',
+ readOnly: false,
+ required: false,
+ colspan: 1,
+ rowspan: 1,
+ placeholder: null,
+ minLength: 0,
+ maxLength: 0,
+ regexPattern: null,
+ visibilityCondition: null,
+ params: {
+ existingColspan: 1,
+ maxColspan: 2
+ }
+ }
+ ],
+ 2: [
+ {
+ id: 'Date0opbi8',
+ name: 'Date',
+ type: 'date',
+ readOnly: false,
+ required: false,
+ colspan: 1,
+ rowspan: 1,
+ placeholder: null,
+ minValue: null,
+ maxValue: null,
+ minDateRangeValue: null,
+ maxDateRangeValue: null,
+ visibilityCondition: null,
+ params: {
+ existingColspan: 1,
+ maxColspan: 2
+ },
+ dateDisplayFormat: 'yyyy-MM-dd'
+ }
+ ]
+ },
+ colspan: 1
+};
+
+export const mockFormWithSimpleSection = {
+ id: 'form-363114eb-35f6-40d0-9908-8bbbe776c3e6',
+ name: 'simplest section',
+ key: 'simplest-section-uzvc7',
+ description: '',
+ version: 0,
+ formDefinition: {
+ tabs: [],
+ fields: [
+ {
+ id: 'Group0wuwv7',
+ name: 'Group',
+ type: 'group',
+ tab: null,
+ params: {
+ hideHeader: false,
+ allowCollapse: false,
+ collapseByDefault: false
+ },
+ numberOfColumns: 1,
+ fields: {
+ 1: [mockSectionWithFields]
+ }
+ }
+ ],
+ outcomes: [],
+ metadata: {},
+ variables: []
+ }
+};
+
+export const mockSectionVisibilityForm = {
+ id: 'form-65e9f07c-44d9-4469-8f5d-74aba3bd7326',
+ name: 'section visibility',
+ key: 'section-visibility-tark1',
+ description: '',
+ version: 0,
+ formDefinition: {
+ tabs: [],
+ fields: [
+ {
+ id: 'Group0sfmn9',
+ name: 'Group',
+ type: 'group',
+ tab: null,
+ params: {
+ hideHeader: false,
+ allowCollapse: false,
+ collapseByDefault: false
+ },
+ numberOfColumns: 1,
+ fields: {
+ 1: [
+ {
+ id: '48e6bfed-b477-4641-86cb-bfa70229a31e',
+ name: 'Section',
+ type: 'section',
+ numberOfColumns: 1,
+ fields: {
+ 1: [
+ {
+ id: 'Text0t23xu',
+ name: 'Text',
+ type: 'text',
+ readOnly: false,
+ required: false,
+ colspan: 1,
+ rowspan: 1,
+ placeholder: null,
+ minLength: 0,
+ maxLength: 0,
+ regexPattern: null,
+ visibilityCondition: {
+ leftType: 'field',
+ leftValue: 'Text0nu6os',
+ operator: '==',
+ rightValue: 'section text',
+ rightType: 'value',
+ nextConditionOperator: '',
+ nextCondition: null
+ },
+ params: {
+ existingColspan: 1,
+ maxColspan: 2
+ }
+ }
+ ]
+ },
+ colspan: 1,
+ visibilityCondition: {
+ leftType: 'field',
+ leftValue: 'Text0n9o62',
+ operator: '==',
+ rightValue: 'section',
+ rightType: 'value',
+ nextConditionOperator: '',
+ nextCondition: null
+ }
+ }
+ ]
+ }
+ },
+ {
+ id: 'f89d427e-dc4d-44df-b47d-4f61a1cea21f',
+ name: 'Label',
+ type: 'container',
+ tab: null,
+ numberOfColumns: 2,
+ fields: {
+ 1: [
+ {
+ id: 'Text0n9o62',
+ name: 'display section',
+ type: 'text',
+ readOnly: false,
+ required: false,
+ colspan: 1,
+ rowspan: 1,
+ placeholder: null,
+ minLength: 0,
+ maxLength: 0,
+ regexPattern: null,
+ visibilityCondition: null,
+ params: {
+ existingColspan: 1,
+ maxColspan: 2
+ }
+ }
+ ],
+ 2: [
+ {
+ id: 'Text0nu6os',
+ name: 'display section field',
+ type: 'text',
+ readOnly: false,
+ required: false,
+ colspan: 1,
+ rowspan: 1,
+ placeholder: null,
+ minLength: 0,
+ maxLength: 0,
+ regexPattern: null,
+ visibilityCondition: null,
+ params: {
+ existingColspan: 1,
+ maxColspan: 2
+ }
+ }
+ ]
+ }
+ }
+ ],
+ outcomes: [],
+ metadata: {},
+ variables: []
+ }
+};
diff --git a/lib/core/src/lib/form/components/mock/form.mock.ts b/lib/core/src/lib/form/components/mock/form.mock.ts
index 8930700eef..680e3172ff 100644
--- a/lib/core/src/lib/form/components/mock/form.mock.ts
+++ b/lib/core/src/lib/form/components/mock/form.mock.ts
@@ -1406,3 +1406,283 @@ export const fakeViewerForm = {
variables: []
}
};
+
+export const mockFormWithSections = {
+ id: 'form-970ddfcf-6d5d-4cbb-ae81-958ade65062c',
+ name: 'simple section',
+ key: 'simple-section-z54vk',
+ description: '',
+ version: 0,
+ tabs: [],
+ fields: [
+ {
+ id: 'Group0bw66i',
+ name: 'Group',
+ type: 'group',
+ tab: null,
+ params: {
+ hideHeader: false,
+ allowCollapse: false,
+ collapseByDefault: false
+ },
+ numberOfColumns: 1,
+ fields: {
+ 1: [
+ {
+ id: '4c0590a9-44e3-415f-9e69-3a3ffe99066b',
+ name: 'Section',
+ type: 'section',
+ numberOfColumns: 4,
+ fields: {
+ 1: [
+ {
+ id: 'Text0xiuw4',
+ name: 'Text in section',
+ type: 'text',
+ readOnly: false,
+ required: false,
+ colspan: 1,
+ rowspan: 1,
+ placeholder: null,
+ minLength: 0,
+ maxLength: 0,
+ regexPattern: null,
+ visibilityCondition: {
+ leftType: 'field',
+ leftValue: 'Text0bbed8',
+ operator: '==',
+ rightValue: 'text inside',
+ rightType: 'value',
+ nextConditionOperator: '',
+ nextCondition: null
+ },
+ params: {
+ existingColspan: 1,
+ maxColspan: 2
+ }
+ }
+ ],
+ 2: [],
+ 3: [
+ {
+ id: 'dateInsideSection',
+ name: 'Date',
+ type: 'date',
+ readOnly: false,
+ required: true,
+ colspan: 2,
+ rowspan: 1,
+ placeholder: null,
+ minValue: null,
+ maxValue: null,
+ minDateRangeValue: null,
+ maxDateRangeValue: null,
+ visibilityCondition: {
+ leftType: 'field',
+ leftValue: 'Text0s7k3m',
+ operator: '==',
+ rightValue: 'date',
+ rightType: 'value',
+ nextConditionOperator: '',
+ nextCondition: null
+ },
+ params: {
+ existingColspan: 1,
+ maxColspan: 2
+ },
+ dateDisplayFormat: 'yyyy-MM-dd'
+ }
+ ]
+ },
+ colspan: 1
+ },
+ {
+ id: '9d0ed068-f6b9-4ddc-ba8b-8ac29b745e1d',
+ name: 'Section',
+ type: 'section',
+ numberOfColumns: 6,
+ fields: {
+ 1: [
+ {
+ id: 'Text0dkzym',
+ name: 'Text',
+ type: 'text',
+ readOnly: false,
+ required: false,
+ colspan: 2,
+ rowspan: 1,
+ placeholder: null,
+ minLength: 0,
+ maxLength: 0,
+ regexPattern: null,
+ visibilityCondition: null,
+ params: {
+ existingColspan: 1,
+ maxColspan: 2
+ }
+ }
+ ],
+ 2: [
+ {
+ id: 'Text0kn8qb',
+ name: 'type text outside',
+ type: 'text',
+ readOnly: false,
+ required: false,
+ colspan: 2,
+ rowspan: 1,
+ placeholder: null,
+ minLength: 0,
+ maxLength: 0,
+ regexPattern: null,
+ visibilityCondition: null,
+ params: {
+ existingColspan: 1,
+ maxColspan: 2
+ }
+ }
+ ],
+ 3: [
+ {
+ id: 'Text0bbed8',
+ name: 'type text inside',
+ type: 'text',
+ readOnly: false,
+ required: false,
+ colspan: 2,
+ rowspan: 1,
+ placeholder: null,
+ minLength: 0,
+ maxLength: 0,
+ regexPattern: null,
+ visibilityCondition: null,
+ params: {
+ existingColspan: 1,
+ maxColspan: 2
+ }
+ }
+ ]
+ },
+ colspan: 1
+ }
+ ]
+ }
+ },
+ {
+ id: 'fc73e4fa-5725-41b2-9185-624d9efd6581',
+ name: 'Label',
+ type: 'container',
+ tab: null,
+ numberOfColumns: 4,
+ fields: {
+ 1: [
+ {
+ id: 'Text0p0v95',
+ name: 'type section',
+ type: 'text',
+ readOnly: false,
+ required: false,
+ colspan: 1,
+ rowspan: 1,
+ placeholder: null,
+ minLength: 0,
+ maxLength: 0,
+ regexPattern: null,
+ visibilityCondition: null,
+ params: {
+ existingColspan: 1,
+ maxColspan: 2
+ }
+ },
+ {
+ id: 'Text0s7k3m',
+ name: 'type date',
+ type: 'text',
+ readOnly: false,
+ required: false,
+ colspan: 1,
+ rowspan: 1,
+ placeholder: null,
+ minLength: 0,
+ maxLength: 0,
+ regexPattern: null,
+ visibilityCondition: null,
+ params: {
+ existingColspan: 1,
+ maxColspan: 2
+ }
+ }
+ ],
+ 2: [
+ {
+ id: 'multilineOutsideSection',
+ name: 'Multiline text',
+ type: 'multi-line-text',
+ readOnly: false,
+ colspan: 1,
+ rowspan: 1,
+ placeholder: null,
+ minLength: 0,
+ maxLength: 0,
+ regexPattern: null,
+ required: false,
+ visibilityCondition: null,
+ params: {
+ existingColspan: 1,
+ maxColspan: 2
+ }
+ }
+ ],
+ 3: [
+ {
+ id: 'Text0opb9w',
+ name: 'Text',
+ type: 'text',
+ readOnly: false,
+ required: false,
+ colspan: 2,
+ rowspan: 1,
+ placeholder: null,
+ minLength: 0,
+ maxLength: 0,
+ regexPattern: null,
+ visibilityCondition: {
+ leftType: 'field',
+ leftValue: 'Text0kn8qb',
+ operator: '==',
+ rightValue: 'text outside',
+ rightType: 'value',
+ nextConditionOperator: '',
+ nextCondition: null
+ },
+ params: {
+ existingColspan: 1,
+ maxColspan: 2
+ }
+ }
+ ]
+ }
+ }
+ ],
+ outcomes: [],
+ metadata: {},
+ variables: [],
+ rules: {
+ fields: {
+ Text0bbed8: {
+ click: [
+ {
+ actions: [
+ {
+ target: 'field.Text0xiuw4',
+ payload: {
+ value: 'updated by form rules!'
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+};
diff --git a/lib/core/src/lib/form/components/widgets/core/container-column.model.ts b/lib/core/src/lib/form/components/widgets/core/container-column.model.ts
index 489e03b210..a301041641 100644
--- a/lib/core/src/lib/form/components/widgets/core/container-column.model.ts
+++ b/lib/core/src/lib/form/components/widgets/core/container-column.model.ts
@@ -15,16 +15,15 @@
* limitations under the License.
*/
-/* eslint-disable @angular-eslint/component-selector */
+import { FormFieldModel } from './form-field.model';
export class ContainerColumnModel {
-
size: number = 12;
- fields: any[] = [];
+ fields: FormFieldModel[] = [];
colspan: number = 1;
rowspan: number = 1;
hasFields(): boolean {
- return this.fields && this.fields.length > 0;
+ return !!this.fields?.length;
}
}
diff --git a/lib/core/src/lib/form/components/widgets/core/form-field.model.spec.ts b/lib/core/src/lib/form/components/widgets/core/form-field.model.spec.ts
index 3bc492b042..9211b5dffc 100644
--- a/lib/core/src/lib/form/components/widgets/core/form-field.model.spec.ts
+++ b/lib/core/src/lib/form/components/widgets/core/form-field.model.spec.ts
@@ -879,6 +879,21 @@ describe('FormFieldModel', () => {
expect(field.numberOfColumns).toBe(123);
});
+ it('should NOT update colspan based on fields colspans for section type', () => {
+ const form = new FormModel();
+ const json = {
+ type: FormFieldTypes.SECTION,
+ numberOfColumns: 2,
+ fields: {
+ column1: [{ id: 'field1', colspan: 2 }],
+ column2: [{ id: 'field2', colspan: 3 }]
+ }
+ };
+ const formField = new FormFieldModel(form, json);
+
+ expect(formField.colspan).toBe(1);
+ });
+
it('should instantiate FormField when has no variable', () => {
const form = new FormModel({});
form.json = {
diff --git a/lib/core/src/lib/form/components/widgets/core/form-field.model.ts b/lib/core/src/lib/form/components/widgets/core/form-field.model.ts
index 4c498f48cb..d724aa207b 100644
--- a/lib/core/src/lib/form/components/widgets/core/form-field.model.ts
+++ b/lib/core/src/lib/form/components/widgets/core/form-field.model.ts
@@ -282,30 +282,34 @@ export class FormFieldModel extends FormWidgetModel {
}
private containerFactory(json: any, form: any): void {
- this.numberOfColumns = json.numberOfColumns || 1;
-
- this.fields = json.fields;
-
+ const { numberOfColumns = 1, fields = {} } = json;
+ this.numberOfColumns = numberOfColumns;
+ this.fields = fields;
this.rowspan = 1;
this.colspan = 1;
- if (json.fields) {
- for (const currentField in json.fields) {
- if (Object.prototype.hasOwnProperty.call(json.fields, currentField)) {
- const col = new ContainerColumnModel();
-
- col.fields = (json.fields[currentField] || []).map((field) => new FormFieldModel(form, field));
- col.rowspan = json.fields[currentField].length;
-
- col.fields.forEach((colFields: any) => {
- this.colspan = colFields.colspan > this.colspan ? colFields.colspan : this.colspan;
- });
-
- this.rowspan = this.rowspan < col.rowspan ? col.rowspan : this.rowspan;
- this.columns.push(col);
- }
+ Object.keys(fields).forEach((currentField) => {
+ if (!Object.prototype.hasOwnProperty.call(fields, currentField)) {
+ return;
}
- }
+
+ const col = new ContainerColumnModel();
+ col.fields = (fields[currentField] || []).map((field: any) => new FormFieldModel(form, field));
+ col.rowspan = fields[currentField].length;
+
+ if (!FormFieldTypes.isSectionType(this.type)) {
+ this.updateContainerColspan(col.fields);
+ }
+
+ this.rowspan = Math.max(this.rowspan, col.rowspan);
+ this.columns.push(col);
+ });
+ }
+
+ private updateContainerColspan(fields: FormFieldModel[]): void {
+ fields.forEach((colField: FormFieldModel) => {
+ this.colspan = Math.max(this.colspan, colField.colspan);
+ });
}
parseValue(json: any): any {
diff --git a/lib/core/src/lib/form/components/widgets/core/form.model.spec.ts b/lib/core/src/lib/form/components/widgets/core/form.model.spec.ts
index b4cb116731..9c4aa2fa2f 100644
--- a/lib/core/src/lib/form/components/widgets/core/form.model.spec.ts
+++ b/lib/core/src/lib/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, mockDisplayExternalPropertyForm } from '../../mock/form.mock';
+import { fakeMetadataForm, mockDisplayExternalPropertyForm, mockFormWithSections } from '../../mock/form.mock';
import { CoreTestingModule } from '../../../../testing';
import { TestBed } from '@angular/core/testing';
@@ -643,4 +643,68 @@ describe('FormModel', () => {
expect(FormFieldTypes.isConstantValueType(displayExternalPropertyWidget.type)).toBeTrue();
expect(displayExternalPropertyWidget.value).toBe('hr');
});
+
+ describe('getFormFields', () => {
+ let form: FormModel;
+
+ beforeEach(() => {
+ form = new FormModel(mockFormWithSections);
+ });
+
+ it('should get all form fields (containers, sections, fields)', () => {
+ const fields = form.getFormFields();
+ expect(fields.length).toBe(13);
+ });
+
+ it('should filter form fields by type inside sections', () => {
+ const fields = form.getFormFields([FormFieldTypes.DATE]);
+ expect(fields.length).toBe(1);
+ expect(fields[0].id).toBe('dateInsideSection');
+ expect(fields[0].type).toBe(FormFieldTypes.DATE);
+ });
+
+ it('should filter form fields by type outside sections', () => {
+ const fields = form.getFormFields([FormFieldTypes.MULTILINE_TEXT]);
+ expect(fields.length).toBe(1);
+ expect(fields[0].id).toBe('multilineOutsideSection');
+ expect(fields[0].type).toBe(FormFieldTypes.MULTILINE_TEXT);
+ });
+
+ it('should filter form fields by multiple types', () => {
+ const fields = form.getFormFields([FormFieldTypes.DATE, FormFieldTypes.MULTILINE_TEXT]);
+ expect(fields.length).toBe(2);
+ expect(fields[0].id).toBe('dateInsideSection');
+ expect(fields[1].id).toBe('multilineOutsideSection');
+ expect(fields[0].type).toBe(FormFieldTypes.DATE);
+ expect(fields[1].type).toBe(FormFieldTypes.MULTILINE_TEXT);
+ });
+
+ it('should return no fields when filtered by a non-existent type', () => {
+ const fields = form.getFormFields(['NON_EXISTENT_TYPE']);
+ expect(fields.length).toBe(0);
+ });
+
+ it('should return fields from cache if available', () => {
+ form.fieldsCache = [new FormFieldModel(form, { type: FormFieldTypes.TEXT }), new FormFieldModel(form, { type: FormFieldTypes.NUMBER })];
+ const fields = form.getFormFields();
+ expect(fields.length).toBe(2);
+ expect(fields[0].type).toBe(FormFieldTypes.TEXT);
+ expect(fields[1].type).toBe(FormFieldTypes.NUMBER);
+ });
+
+ it('should return filtered fields from cache if available', () => {
+ form.fieldsCache = [
+ new FormFieldModel(form, { type: FormFieldTypes.TEXT }),
+ new FormFieldModel(form, { type: FormFieldTypes.AMOUNT }),
+ new FormFieldModel(form, { type: FormFieldTypes.DATE }),
+ new FormFieldModel(form, { type: FormFieldTypes.NUMBER })
+ ];
+
+ const fields = form.getFormFields([FormFieldTypes.AMOUNT, FormFieldTypes.DATE, FormFieldTypes.NUMBER]);
+ expect(fields.length).toBe(3);
+ expect(fields[0].type).toBe(FormFieldTypes.AMOUNT);
+ expect(fields[1].type).toBe(FormFieldTypes.DATE);
+ expect(fields[2].type).toBe(FormFieldTypes.NUMBER);
+ });
+ });
});
diff --git a/lib/core/src/lib/form/components/widgets/core/form.model.ts b/lib/core/src/lib/form/components/widgets/core/form.model.ts
index 42dcb99dde..5dfe1c8b6a 100644
--- a/lib/core/src/lib/form/components/widgets/core/form.model.ts
+++ b/lib/core/src/lib/form/components/widgets/core/form.model.ts
@@ -340,28 +340,63 @@ export class FormModel implements ProcessFormModel {
return this.fieldsCache.find((field) => field.id === fieldId);
}
- getFormFields(): FormFieldModel[] {
- if (this.fieldsCache.length > 0) {
- return this.fieldsCache;
- } else {
- const formFieldModel: FormFieldModel[] = [];
-
- for (let i = 0; i < this.fields.length; i++) {
- const field = this.fields[i];
-
- if (field instanceof ContainerModel) {
- formFieldModel.push(field.field);
-
- field.field.columns.forEach((column) => {
- formFieldModel.push(...column.fields);
- });
- } else {
- formFieldModel.push(field);
- }
- }
-
- return formFieldModel;
+ getFormFields(filterTypes?: string[]): FormFieldModel[] {
+ if (this.fieldsCache?.length) {
+ return this.filterFieldsByType(this.fieldsCache, filterTypes);
}
+
+ const formFieldModel: FormFieldModel[] = [];
+ this.processFields(this.fields, formFieldModel);
+ return this.filterFieldsByType(formFieldModel, filterTypes);
+ }
+
+ private processFields(fields: (ContainerModel | FormFieldModel)[], formFieldModel: FormFieldModel[]): void {
+ fields.forEach((field) => {
+ if (this.isSectionField(field)) {
+ this.handleSectionField(field, formFieldModel);
+ } else if (this.isContainerField(field)) {
+ this.handleContainerField(field, formFieldModel);
+ } else {
+ this.handleSingleField(field, formFieldModel);
+ }
+ });
+ }
+
+ private isContainerField(field: ContainerModel | FormFieldModel): field is ContainerModel {
+ return field instanceof ContainerModel;
+ }
+
+ private isSectionField(field: ContainerModel | FormFieldModel): field is FormFieldModel {
+ return field.type === FormFieldTypes.SECTION;
+ }
+
+ private handleSectionField(section: FormFieldModel, formFieldModel: FormFieldModel[]): void {
+ formFieldModel.push(section);
+ section.columns.forEach((column) => {
+ this.processFields(column.fields, formFieldModel);
+ });
+ }
+
+ private handleContainerField(container: ContainerModel, formFieldModel: FormFieldModel[]): void {
+ formFieldModel.push(container.field);
+ container.field.columns.forEach((column) => {
+ this.processFields(column.fields, formFieldModel);
+ });
+ }
+
+ private handleSingleField(field: FormFieldModel, formFieldModel: FormFieldModel[]): void {
+ formFieldModel.push(field);
+ if (field.fields) {
+ this.processFields(Object.values(field.fields), formFieldModel);
+ }
+ }
+
+ private filterFieldsByType(fields: FormFieldModel[], types?: string[]): FormFieldModel[] {
+ if (!types?.length) {
+ return fields;
+ }
+
+ return fields.filter((field) => types.includes(field?.type));
}
markAsInvalid(): void {
diff --git a/lib/core/src/lib/form/components/widgets/display-text/display-text.widget.scss b/lib/core/src/lib/form/components/widgets/display-text/display-text.widget.scss
index c9b475ef35..5790d8f248 100644
--- a/lib/core/src/lib/form/components/widgets/display-text/display-text.widget.scss
+++ b/lib/core/src/lib/form/components/widgets/display-text/display-text.widget.scss
@@ -4,4 +4,5 @@
font-weight: var(--adf-readonly-text-font-weight, var(--adf-form-label-font-weight, var(--theme-font-weight)));
color: var(--adf-readonly-text-color, var(--adf-form-label-color, var(--theme-text-color)));
line-height: normal;
+ word-break: break-word;
}
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 c0f4dfaf7f..52127862bb 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
@@ -152,12 +152,12 @@ describe('FormComponent UI and visibility', () => {
fixture.detectChanges();
const firstEl = fixture.debugElement.query(By.css('#field-country-container'));
- expect(firstEl.nativeElement.style.visibility).toBe('hidden');
+ expect(firstEl.nativeElement.style.display).toBe('none');
const secondEl = fixture.debugElement.query(By.css('#name'));
expect(secondEl).not.toBeNull();
expect(secondEl).toBeDefined();
- expect(fixture.nativeElement.querySelector('#field-name-container').style.visibility).not.toBe('hidden');
+ expect(fixture.nativeElement.querySelector('#field-name-container').style.display).toBe('block');
});
it('should hide the field based on the previous one', () => {
@@ -171,10 +171,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').style.visibility).not.toBe('hidden');
+ expect(fixture.nativeElement.querySelector('#field-name-container').style.display).toBe('block');
const secondEl = fixture.debugElement.query(By.css('#field-country-container'));
- expect(secondEl.nativeElement.style.visibility).toBe('hidden');
+ expect(secondEl.nativeElement.style.display).toBe('none');
});
it('should show the hidden field when the visibility condition change to true', () => {
@@ -186,10 +186,10 @@ describe('FormComponent UI and visibility', () => {
fixture.detectChanges();
let firstEl = fixture.debugElement.query(By.css('#field-country-container'));
- expect(firstEl.nativeElement.style.visibility).toBe('hidden');
+ expect(firstEl.nativeElement.style.display).toBe('none');
const secondEl = fixture.debugElement.query(By.css('#field-name-container'));
- expect(secondEl.nativeElement.style.visibility).not.toBe('hidden');
+ expect(secondEl.nativeElement.style.display).toBe('block');
const inputElement = fixture.nativeElement.querySelector('#name');
inputElement.value = 'italy';
@@ -197,7 +197,7 @@ describe('FormComponent UI and visibility', () => {
fixture.detectChanges();
firstEl = fixture.debugElement.query(By.css('#field-country-container'));
- expect(firstEl.nativeElement.style.visibility).not.toBe('hidden');
+ expect(firstEl.nativeElement.style.display).toBe('block');
});
});
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 91257294e7..897b17ecf4 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
@@ -511,9 +511,9 @@ describe('TaskFormComponent', () => {
fixture.detectChanges();
await fixture.whenStable();
const inputThreeContainer = fixture.nativeElement.querySelector('#field-text3-container');
- expect(inputThreeContainer.style.visibility).toBe('hidden');
+ expect(inputThreeContainer.style.display).toBe('none');
const completeOutcomeButton: HTMLButtonElement = fixture.nativeElement.querySelector('#adf-form-complete');
- expect(completeOutcomeButton.style.visibility).not.toBe('hidden');
+ expect(completeOutcomeButton.style.display).not.toBe('none');
completeOutcomeButton.click();
fixture.detectChanges();
});