mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +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;
|
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);
|
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 {
|
private shouldAddRow(): boolean {
|
||||||
return !this.params.maxNumberOfRows || this.rows.length < this.params.maxNumberOfRows;
|
return !this.params.maxNumberOfRows || this.rows.length < this.params.maxNumberOfRows;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -820,6 +820,50 @@ describe('FormModel', () => {
|
|||||||
describe('FormModel - isFieldOrParentHidden', () => {
|
describe('FormModel - isFieldOrParentHidden', () => {
|
||||||
let form: FormModel;
|
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(() => {
|
beforeEach(() => {
|
||||||
form = new FormModel();
|
form = new FormModel();
|
||||||
});
|
});
|
||||||
@@ -998,6 +1042,154 @@ describe('FormModel', () => {
|
|||||||
expect(testForm.isFieldOrParentHidden(field)).toBe(true);
|
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', () => {
|
it('should return false for visible field with visible parents - ContainerModel', () => {
|
||||||
const formJson = {
|
const formJson = {
|
||||||
id: 'test-form',
|
id: 'test-form',
|
||||||
|
|||||||
@@ -613,13 +613,30 @@ export class FormModel implements ProcessFormModel {
|
|||||||
|
|
||||||
private getColumnsFromElement(element: ContainerModel | FormFieldModel): ContainerColumnModel[] | null {
|
private getColumnsFromElement(element: ContainerModel | FormFieldModel): ContainerColumnModel[] | null {
|
||||||
if (element instanceof ContainerModel) {
|
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) {
|
} else if (element instanceof FormFieldModel && element.type === FormFieldTypes.SECTION) {
|
||||||
return element.columns || null;
|
return element.columns || null;
|
||||||
}
|
}
|
||||||
return 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(
|
private searchFieldsInColumns(
|
||||||
columns: ContainerColumnModel[],
|
columns: ContainerColumnModel[],
|
||||||
parentElement: ContainerModel | FormFieldModel,
|
parentElement: ContainerModel | FormFieldModel,
|
||||||
|
|||||||
Reference in New Issue
Block a user