mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-02 17:53:30 +00:00
AAE-49688 fix for hidden fields in groups holding up validations (#12135)
This commit is contained in:
@@ -483,10 +483,30 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
return;
|
||||
}
|
||||
|
||||
this.rows.push(this.createRow(fields, form, this.rows.length));
|
||||
const row = this.createRow(fields, form, this.rows.length);
|
||||
this.copyParentVisibilityValidationState(this.columns, row.columns);
|
||||
this.rows.push(row);
|
||||
this.form.onRepeatableSectionRowCountChanged(this);
|
||||
}
|
||||
|
||||
private copyParentVisibilityValidationState(sourceColumns: ContainerColumnModel[], targetColumns: ContainerColumnModel[]): void {
|
||||
const sourceFields = sourceColumns.flatMap((column) => column.fields);
|
||||
|
||||
for (const targetColumn of targetColumns) {
|
||||
for (const targetField of targetColumn.fields) {
|
||||
const sourceField = sourceFields.find((field) => field.json.id === targetField.json.id);
|
||||
if (!sourceField) {
|
||||
continue;
|
||||
}
|
||||
|
||||
targetField.checkParentVisibilityForValidation = sourceField.checkParentVisibilityForValidation;
|
||||
if (targetField.type === FormFieldTypes.SECTION) {
|
||||
this.copyParentVisibilityValidationState(sourceField.columns, targetField.columns);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private shouldAddRow(): boolean {
|
||||
return !this.params.maxNumberOfRows || this.rows.length < this.params.maxNumberOfRows;
|
||||
}
|
||||
|
||||
@@ -820,6 +820,50 @@ describe('FormModel', () => {
|
||||
describe('FormModel - isFieldOrParentHidden', () => {
|
||||
let form: FormModel;
|
||||
|
||||
const repeatableSectionFormJson = (checkParentVisibilityForValidation: boolean) => ({
|
||||
id: 'test-form',
|
||||
name: 'Test Form',
|
||||
fields: [
|
||||
{
|
||||
id: 'repeatableSection1',
|
||||
type: FormFieldTypes.REPEATABLE_SECTION,
|
||||
numberOfColumns: 1,
|
||||
params: { initialNumberOfRows: 2 },
|
||||
fields: {
|
||||
1: [{ id: 'field1', type: FormFieldTypes.TEXT, required: true, checkParentVisibilityForValidation }]
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const sectionInRepeatableSectionFormJson = (checkParentVisibilityForValidation: boolean) => ({
|
||||
id: 'test-form',
|
||||
name: 'Test Form',
|
||||
fields: [
|
||||
{
|
||||
id: 'repeatableSection1',
|
||||
type: FormFieldTypes.REPEATABLE_SECTION,
|
||||
numberOfColumns: 1,
|
||||
params: { initialNumberOfRows: 2 },
|
||||
fields: {
|
||||
1: [
|
||||
{
|
||||
id: 'section1',
|
||||
type: FormFieldTypes.SECTION,
|
||||
numberOfColumns: 1,
|
||||
fields: {
|
||||
1: [{ id: 'field1', type: FormFieldTypes.TEXT, required: true, checkParentVisibilityForValidation }]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const getRepeatableSectionField = (repeatableSection: ContainerModel, rowIndex: number): FormFieldModel =>
|
||||
repeatableSection.field.rows[rowIndex].columns[0].fields[0];
|
||||
|
||||
beforeEach(() => {
|
||||
form = new FormModel();
|
||||
});
|
||||
@@ -998,6 +1042,154 @@ describe('FormModel', () => {
|
||||
expect(testForm.isFieldOrParentHidden(field)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true for field in the first row of a hidden repeatable section when opt-in is enabled', () => {
|
||||
const testForm = new FormModel(repeatableSectionFormJson(true));
|
||||
testForm.enableParentVisibilityCheck = true;
|
||||
const repeatableSection = testForm.fields[0] as ContainerModel;
|
||||
repeatableSection.field.isVisible = false;
|
||||
const field = getRepeatableSectionField(repeatableSection, 0);
|
||||
field.isVisible = true;
|
||||
expect(testForm.isFieldOrParentHidden(field)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true for field in a later row of a hidden repeatable section when opt-in is enabled', () => {
|
||||
const testForm = new FormModel(repeatableSectionFormJson(true));
|
||||
testForm.enableParentVisibilityCheck = true;
|
||||
const repeatableSection = testForm.fields[0] as ContainerModel;
|
||||
repeatableSection.field.isVisible = false;
|
||||
const field = getRepeatableSectionField(repeatableSection, 1);
|
||||
field.isVisible = true;
|
||||
expect(testForm.isFieldOrParentHidden(field)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true for field in a section nested in a hidden repeatable section when opt-in is enabled', () => {
|
||||
const testForm = new FormModel(sectionInRepeatableSectionFormJson(true));
|
||||
testForm.enableParentVisibilityCheck = true;
|
||||
const repeatableSection = testForm.fields[0] as ContainerModel;
|
||||
repeatableSection.field.isVisible = false;
|
||||
const nestedSection = getRepeatableSectionField(repeatableSection, 1);
|
||||
nestedSection.isVisible = true;
|
||||
const field = nestedSection.columns[0].fields[0];
|
||||
field.isVisible = true;
|
||||
expect(testForm.isFieldOrParentHidden(field)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for field in a later row of a visible repeatable section when opt-in is enabled', () => {
|
||||
const testForm = new FormModel(repeatableSectionFormJson(true));
|
||||
testForm.enableParentVisibilityCheck = true;
|
||||
const repeatableSection = testForm.fields[0] as ContainerModel;
|
||||
repeatableSection.field.isVisible = true;
|
||||
const field = getRepeatableSectionField(repeatableSection, 1);
|
||||
field.isVisible = true;
|
||||
expect(testForm.isFieldOrParentHidden(field)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for field in hidden repeatable section when opt-in is disabled - backward compatible', () => {
|
||||
const testForm = new FormModel(repeatableSectionFormJson(false));
|
||||
const repeatableSection = testForm.fields[0] as ContainerModel;
|
||||
repeatableSection.field.isVisible = false;
|
||||
const field = getRepeatableSectionField(repeatableSection, 1);
|
||||
field.isVisible = true;
|
||||
expect(testForm.isFieldOrParentHidden(field)).toBe(false);
|
||||
});
|
||||
|
||||
it('should enable the parent visibility check on a repeatable section field added after model opt-in', () => {
|
||||
const testForm = new FormModel(repeatableSectionFormJson(false));
|
||||
testForm.enableParentVisibilityCheck = true;
|
||||
testForm.getFormFields().forEach((field) => (field.checkParentVisibilityForValidation = true));
|
||||
const repeatableSection = testForm.fields[0] as ContainerModel;
|
||||
|
||||
repeatableSection.field.addRow(repeatableSection.json.fields, repeatableSection.form);
|
||||
|
||||
const field = getRepeatableSectionField(repeatableSection, 2);
|
||||
expect(field.checkParentVisibilityForValidation).toBe(true);
|
||||
});
|
||||
|
||||
it('should preserve selective parent visibility checks when adding a repeatable section row', () => {
|
||||
const testForm = new FormModel({
|
||||
id: 'test-form',
|
||||
name: 'Test Form',
|
||||
fields: [
|
||||
{
|
||||
id: 'repeatableSection1',
|
||||
type: FormFieldTypes.REPEATABLE_SECTION,
|
||||
numberOfColumns: 1,
|
||||
params: { initialNumberOfRows: 1 },
|
||||
fields: {
|
||||
1: [
|
||||
{ id: 'optedInField', type: FormFieldTypes.TEXT },
|
||||
{ id: 'optedOutField', type: FormFieldTypes.TEXT }
|
||||
]
|
||||
}
|
||||
},
|
||||
{ id: 'unrelatedField', type: FormFieldTypes.TEXT }
|
||||
]
|
||||
});
|
||||
testForm.enableParentVisibilityCheck = true;
|
||||
const repeatableSection = testForm.fields[0] as ContainerModel;
|
||||
const sourceFields = repeatableSection.field.rows[0].columns[0].fields;
|
||||
sourceFields[0].checkParentVisibilityForValidation = true;
|
||||
|
||||
repeatableSection.field.addRow(repeatableSection.json.fields, repeatableSection.form);
|
||||
|
||||
const addedFields = repeatableSection.field.rows[1].columns[0].fields;
|
||||
expect(addedFields[0].checkParentVisibilityForValidation).toBe(true);
|
||||
expect(addedFields[1].checkParentVisibilityForValidation).toBe(false);
|
||||
expect(testForm.getFieldById('unrelatedField').checkParentVisibilityForValidation).toBe(false);
|
||||
});
|
||||
|
||||
it('should copy nested field parent visibility checks to a new repeatable section row', () => {
|
||||
const testForm = new FormModel(sectionInRepeatableSectionFormJson(false));
|
||||
testForm.enableParentVisibilityCheck = true;
|
||||
const repeatableSection = testForm.fields[0] as ContainerModel;
|
||||
const sourceSection = getRepeatableSectionField(repeatableSection, 0);
|
||||
sourceSection.columns[0].fields[0].checkParentVisibilityForValidation = true;
|
||||
|
||||
repeatableSection.field.addRow(repeatableSection.json.fields, repeatableSection.form);
|
||||
|
||||
const addedSection = getRepeatableSectionField(repeatableSection, 2);
|
||||
expect(addedSection.checkParentVisibilityForValidation).toBe(false);
|
||||
expect(addedSection.columns[0].fields[0].checkParentVisibilityForValidation).toBe(true);
|
||||
});
|
||||
|
||||
it('should copy template parent visibility checks when adding the first repeatable section row', () => {
|
||||
const formJson = repeatableSectionFormJson(false);
|
||||
formJson.fields[0].params.initialNumberOfRows = 0;
|
||||
const testForm = new FormModel(formJson);
|
||||
testForm.enableParentVisibilityCheck = true;
|
||||
const repeatableSection = testForm.fields[0] as ContainerModel;
|
||||
repeatableSection.field.columns[0].fields[0].checkParentVisibilityForValidation = true;
|
||||
|
||||
repeatableSection.field.addRow(repeatableSection.json.fields, repeatableSection.form);
|
||||
|
||||
const field = getRepeatableSectionField(repeatableSection, 0);
|
||||
expect(field.checkParentVisibilityForValidation).toBe(true);
|
||||
});
|
||||
|
||||
it('should exclude a required field added to a hidden repeatable section from validation after model opt-in', () => {
|
||||
const testForm = new FormModel(repeatableSectionFormJson(false));
|
||||
testForm.enableParentVisibilityCheck = true;
|
||||
testForm.getFormFields().forEach((field) => (field.checkParentVisibilityForValidation = true));
|
||||
const repeatableSection = testForm.fields[0] as ContainerModel;
|
||||
repeatableSection.field.addRow(repeatableSection.json.fields, repeatableSection.form);
|
||||
repeatableSection.field.isVisible = false;
|
||||
|
||||
testForm.validateForm();
|
||||
|
||||
expect(testForm.isValid).toBe(true);
|
||||
});
|
||||
|
||||
it('should preserve validation for a required field added to a hidden repeatable section without model opt-in', () => {
|
||||
const testForm = new FormModel(repeatableSectionFormJson(false));
|
||||
const repeatableSection = testForm.fields[0] as ContainerModel;
|
||||
repeatableSection.field.addRow(repeatableSection.json.fields, repeatableSection.form);
|
||||
repeatableSection.field.isVisible = false;
|
||||
|
||||
testForm.validateForm();
|
||||
|
||||
expect(testForm.isValid).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for visible field with visible parents - ContainerModel', () => {
|
||||
const formJson = {
|
||||
id: 'test-form',
|
||||
|
||||
@@ -613,13 +613,30 @@ export class FormModel implements ProcessFormModel {
|
||||
|
||||
private getColumnsFromElement(element: ContainerModel | FormFieldModel): ContainerColumnModel[] | null {
|
||||
if (element instanceof ContainerModel) {
|
||||
return element.field?.columns || null;
|
||||
return FormFieldTypes.isRepeatableSectionType(element.field?.type)
|
||||
? this.getColumnsFromAllRows(element.field)
|
||||
: element.field?.columns || null;
|
||||
} else if (element instanceof FormFieldModel && element.type === FormFieldTypes.SECTION) {
|
||||
return element.columns || null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private getColumnsFromAllRows(field: FormFieldModel): ContainerColumnModel[] | null {
|
||||
if (!field.rows?.length) {
|
||||
return field.columns || null;
|
||||
}
|
||||
|
||||
const columns: ContainerColumnModel[] = [];
|
||||
for (const row of field.rows) {
|
||||
if (row?.columns?.length) {
|
||||
columns.push(...row.columns);
|
||||
}
|
||||
}
|
||||
|
||||
return columns.length > 0 ? columns : null;
|
||||
}
|
||||
|
||||
private searchFieldsInColumns(
|
||||
columns: ContainerColumnModel[],
|
||||
parentElement: ContainerModel | FormFieldModel,
|
||||
|
||||
Reference in New Issue
Block a user