AAE-34675 Fix default selection required (#10860)

* fix default selection required

* rename test

* dropdown form field return object

* dropdown form field return object

* dropdown form field return object

* fix test

* Update lib/core/src/lib/form/components/widgets/core/form-field.model.spec.ts

Co-authored-by: Ehsan Rezaei <ehsan.rezaei@hyland.com>

* Update lib/core/src/lib/form/components/widgets/core/form-field.model.ts

Co-authored-by: Ehsan Rezaei <ehsan.rezaei@hyland.com>

---------

Co-authored-by: Ehsan Rezaei <ehsan.rezaei@hyland.com>
This commit is contained in:
Eugenio Romano
2025-05-15 21:26:17 +02:00
committed by GitHub
parent 9c6a1901c6
commit b4eee9d631
7 changed files with 138 additions and 11 deletions

View File

@@ -146,7 +146,7 @@ describe('FormFieldModel', () => {
}); });
expect(field.options).toEqual([{ id: 'id_one', name: 'One' }]); expect(field.options).toEqual([{ id: 'id_one', name: 'One' }]);
expect(field.value).toEqual('id_one'); expect(field.value).toEqual({ id: 'id_one', name: 'One' });
}); });
it('should add value (selected options) to field options if NOT present (multiple selection)', () => { it('should add value (selected options) to field options if NOT present (multiple selection)', () => {
@@ -176,7 +176,7 @@ describe('FormFieldModel', () => {
expect(field.hasEmptyValue).toBe(true); expect(field.hasEmptyValue).toBe(true);
expect(field.emptyOption).toEqual({ id: 'empty', name: 'Chose one...' }); expect(field.emptyOption).toEqual({ id: 'empty', name: 'Chose one...' });
expect(field.value).toEqual('empty'); expect(field.value).toEqual({ id: 'empty', name: 'Chose one...' });
}); });
it('should set hasEmptyValue to true if "empty" option is present in options', () => { it('should set hasEmptyValue to true if "empty" option is present in options', () => {
@@ -272,7 +272,8 @@ describe('FormFieldModel', () => {
options: [], options: [],
value: { id: 'delayed-option-id', name: 'Delayed option' } value: { id: 'delayed-option-id', name: 'Delayed option' }
}); });
expect(field.value).toBe('delayed-option-id');
expect(field.value).toEqual({ id: 'delayed-option-id', name: 'Delayed option' });
}); });
}); });
}); });
@@ -770,7 +771,7 @@ describe('FormFieldModel', () => {
]; ];
}); });
it('should update form with selected option and options from which we chose', () => { it('should update form with selected option and options from which we chose when is a string', () => {
field.value = 'restOpt2'; field.value = 'restOpt2';
field.updateForm(); field.updateForm();
@@ -1023,7 +1024,7 @@ describe('FormFieldModel', () => {
expect(field.options).toEqual(staticOptions); expect(field.options).toEqual(staticOptions);
}); });
it('should selected option appear in form values', () => { it('should selected option appear in form values string', () => {
const field = getFieldConfig('manual', staticOptions, 'opt2'); const field = getFieldConfig('manual', staticOptions, 'opt2');
field.updateForm(); field.updateForm();
@@ -1031,6 +1032,15 @@ describe('FormFieldModel', () => {
expect(field.value).toEqual('opt2'); expect(field.value).toEqual('opt2');
expect(field.form.values['dropdown_field']).toEqual({ id: 'opt2', name: 'Option 2' }); expect(field.form.values['dropdown_field']).toEqual({ id: 'opt2', name: 'Option 2' });
}); });
it('should selected option appear in form values obj', () => {
const field = getFieldConfig('manual', staticOptions, { id: 'opt3', name: 'opt3' });
field.updateForm();
expect(field.value).toEqual({ id: 'opt3', name: 'opt3' });
expect(field.form.values['dropdown_field']).toEqual({ id: 'opt3', name: 'opt3' });
});
}); });
describe('radio buttons field', () => { describe('radio buttons field', () => {

View File

@@ -331,13 +331,13 @@ export class FormFieldModel extends FormWidgetModel {
const isEmptyValue = !value || [this.emptyOption.id, this.emptyOption.name].includes(value); const isEmptyValue = !value || [this.emptyOption.id, this.emptyOption.name].includes(value);
if (isEmptyValue) { if (isEmptyValue) {
return this.emptyOption.id; return this.emptyOption;
} }
} }
if (this.isValidOption(value)) { if (this.isValidOption(value)) {
this.addOption({ id: value.id, name: value.name }); this.addOption({ id: value.id, name: value.name });
return value.id; return value;
} }
if (this.hasMultipleValues) { if (this.hasMultipleValues) {
@@ -436,6 +436,17 @@ export class FormFieldModel extends FormWidgetModel {
this.form.values[this.id] = matchingOption || null; this.form.values[this.id] = matchingOption || null;
} }
if (typeof this.value === 'object') {
if (this.value.id === 'empty' || this.value.id === '') {
this.form.values[this.id] = null;
break;
}
const matchingOption: FormFieldOption = this.options.find((opt) => opt.id === this.value.id);
this.form.values[this.id] = matchingOption;
}
break; break;
} }
case FormFieldTypes.RADIO_BUTTONS: { case FormFieldTypes.RADIO_BUTTONS: {

View File

@@ -983,6 +983,34 @@ describe('DropdownCloudWidgetComponent', () => {
expect(widget.field.options.length).toEqual(0); expect(widget.field.options.length).toEqual(0);
}; };
it('should set dropdownControl value without emitting events if the mapping is a string', () => {
widget.field = {
value: 'testValue',
options: [],
isVisible: true
} as any; // Mock field
spyOn(widget.dropdownControl, 'setValue').and.callThrough();
widget['setFormControlValue']();
expect(widget.dropdownControl.setValue).toHaveBeenCalledWith({ id: 'testValue', name: '' }, { emitEvent: false });
expect(widget.dropdownControl.value).toEqual({ id: 'testValue', name: '' });
});
it('should set dropdownControl value without emitting events if is an object', () => {
widget.field = {
value: { id: 'testValueObj', name: 'testValueObjName' },
options: [],
isVisible: true
} as any; // Mock field
spyOn(widget.dropdownControl, 'setValue').and.callThrough();
widget['setFormControlValue']();
expect(widget.dropdownControl.setValue).toHaveBeenCalledWith({ id: 'testValueObj', name: 'testValueObjName' }, { emitEvent: false });
expect(widget.dropdownControl.value).toEqual({ id: 'testValueObj', name: 'testValueObjName' });
});
it('should display options persisted from process variable', async () => { it('should display options persisted from process variable', async () => {
widget.field = getVariableDropdownWidget( widget.field = getVariableDropdownWidget(
'variables.json-variable', 'variables.json-variable',

View File

@@ -195,7 +195,15 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
} }
private setFormControlValue(): void { private setFormControlValue(): void {
this.dropdownControl.setValue(this.field?.value, { emitEvent: false }); if (Array.isArray(this.field.value)) {
this.dropdownControl.setValue(this.field?.value, { emitEvent: false });
} else if (this.field?.value && typeof this.field?.value === 'object') {
this.dropdownControl.setValue({ id: this.field?.value.id, name: this.field?.value.name }, { emitEvent: false });
} else if (this.field.value === null) {
this.dropdownControl.setValue(this.field?.value, { emitEvent: false });
} else {
this.dropdownControl.setValue({ id: this.field?.value, name: '' }, { emitEvent: false });
}
} }
private updateFormControlState(): void { private updateFormControlState(): void {
@@ -469,7 +477,11 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
const fieldValueIds = this.field.value.map((valueOption) => valueOption.id); const fieldValueIds = this.field.value.map((valueOption) => valueOption.id);
return fieldValueIds.every((valueOptionId) => optionIdList.includes(valueOptionId)); return fieldValueIds.every((valueOptionId) => optionIdList.includes(valueOptionId));
} else { } else {
return [...this.field.options].map((option) => option.id).includes(this.field.value); if (this.field?.value && typeof this.field?.value === 'object') {
return [...this.field.options].map((option) => option.id).includes(this.field.value.id);
} else {
return [...this.field.options].map((option) => option.id).includes(this.field.value);
}
} }
} }

View File

@@ -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 { FormFieldModel } from '@alfresco/adf-core';
import { FormControl } from '@angular/forms';
import { defaultValueValidator } from './validators';
import { DEFAULT_OPTION } from './dropdown-cloud.widget';
describe('defaultValueValidator', () => {
let mockField: FormFieldModel;
beforeEach(() => {
mockField = new FormFieldModel(null, {
options: [
{ id: DEFAULT_OPTION.id, name: DEFAULT_OPTION.name },
{ id: 'opt_1', name: 'Option 1' },
{ id: 'opt_2', name: 'Option 2' }
]
});
});
it('should return null when a valid option is selected', () => {
const validator = defaultValueValidator(mockField);
const control = new FormControl({ id: 'opt_1' });
const result = validator(control);
expect(result).toBeNull();
});
it('should return a required error when no valid option is selected', () => {
const validator = defaultValueValidator(mockField);
const control = new FormControl(null);
const result = validator(control);
expect(result).toEqual({ required: true });
});
it('should return a required error when the default "choose one" option is selected', () => {
const validator = defaultValueValidator(mockField);
const control = new FormControl(DEFAULT_OPTION.id);
const result = validator(control);
expect(result).toEqual({ required: true });
});
});

View File

@@ -30,6 +30,7 @@ export const defaultValueValidator =
const isSomeOptionSelected = optionsWithNoDefaultValue.some((dropdownOption) => { const isSomeOptionSelected = optionsWithNoDefaultValue.some((dropdownOption) => {
const isOptionSelected = dropdownOption.id === control.value?.id; const isOptionSelected = dropdownOption.id === control.value?.id;
return isOptionSelected; return isOptionSelected;
}); });

View File

@@ -941,7 +941,7 @@ describe('FormComponent', () => {
let dropdownField = formFields.find((field) => field.id === 'dropdownId'); let dropdownField = formFields.find((field) => field.id === 'dropdownId');
let radioField = formFields.find((field) => field.id === 'radio'); let radioField = formFields.find((field) => field.id === 'radio');
expect(dropdownField.value).toBe('empty'); expect(dropdownField.value).toEqual({ id: 'empty', name: 'Choose one...' });
expect(radioField.value).toBeNull(); expect(radioField.value).toBeNull();
const formValues: any = {}; const formValues: any = {};
@@ -961,7 +961,10 @@ describe('FormComponent', () => {
dropdownField = formFields.find((field) => field.id === 'dropdownId'); dropdownField = formFields.find((field) => field.id === 'dropdownId');
radioField = formFields.find((field) => field.id === 'radio'); radioField = formFields.find((field) => field.id === 'radio');
expect(dropdownField.value).toBe('dropdown_option_2'); expect(dropdownField.value).toEqual({
id: 'dropdown_option_2',
name: 'Dropdown option 2'
});
expect(radioField.value).toBe('radio_option_3'); expect(radioField.value).toBe('radio_option_3');
}); });