AAE-22947 Update form-field.model

This commit is contained in:
wiktord2000 2024-06-11 09:55:45 +02:00
parent 7c2aeb060b
commit 44e2911eaf
No known key found for this signature in database
2 changed files with 107 additions and 70 deletions

View File

@ -115,11 +115,66 @@ describe('FormFieldModel', () => {
it('should parse and leave dropdown value as is', () => { it('should parse and leave dropdown value as is', () => {
const field = new FormFieldModel(new FormModel(), { const field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.DROPDOWN, type: FormFieldTypes.DROPDOWN,
options: [], options: [{ id: 'one', name: 'One' }],
value: 'deferred' value: { id: 'one', name: 'One' }
}); });
expect(field.value).toBe('deferred'); expect(field.value).toEqual({ id: 'one', name: 'One' });
expect(field.options).toEqual([{ id: 'one', name: 'One' }]);
});
it('should filter out invalid options on field initialization', () => {
const field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.DROPDOWN,
options: [{ id: 'valid', name: 'Valid' }, { id: 'invalid' }, { name: 'invalid' }, [], {}, 'invalid'],
value: null
});
expect(field.options).toEqual([{ id: 'valid', name: 'Valid' }]);
});
it('should add value to field options if NOT present', () => {
const field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.DROPDOWN,
options: [],
value: { id: 'one', name: 'One' }
});
expect(field.value).toEqual({ id: 'one', name: 'One' });
expect(field.options).toEqual([{ id: 'one', name: 'One' }]);
});
it('should assign "empty" option as value if value is null and "empty" option is present in options', () => {
const field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.DROPDOWN,
options: [
{ id: 'empty', name: 'Chose option...' },
{ id: 'one', name: 'One' }
],
value: null
});
expect(field.value).toEqual({ id: 'empty', name: 'Chose option...' });
});
it('should assign null to value when value has invalid option object', () => {
const field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.DROPDOWN,
options: [{ id: 'one', name: 'One' }],
value: { id: 'one' }
});
expect(field.value).toBe(null);
});
it('should set hasEmptyValue to true if "empty" option is present in options', () => {
const field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.DROPDOWN,
options: [{ id: 'empty', name: 'Chose option...' }],
value: null
});
expect(field.hasEmptyValue).toBe(true);
}); });
it('should add value to field options if NOT present', () => { it('should add value to field options if NOT present', () => {
@ -144,7 +199,7 @@ describe('FormFieldModel', () => {
}); });
expect(field.hasEmptyValue).toBe(true); expect(field.hasEmptyValue).toBe(true);
expect(field.emptyOption).toEqual({ id: 'empty', name: 'Chose one...' }); expect(field.emptyValueOption).toEqual({ id: 'empty', name: 'Chose one...' });
expect(field.value).toEqual('empty'); expect(field.value).toEqual('empty');
}); });
@ -156,7 +211,7 @@ describe('FormFieldModel', () => {
}); });
expect(field.hasEmptyValue).toBe(true); expect(field.hasEmptyValue).toBe(true);
expect(field.emptyOption).toEqual({ id: 'empty', name: 'Choose one...' }); expect(field.emptyValueOption).toEqual({ id: 'empty', name: 'Choose one...' });
}); });
it('should add default "empty" option to the options if hasEmptyValue is true but "empty" option is not present', () => { it('should add default "empty" option to the options if hasEmptyValue is true but "empty" option is not present', () => {
@ -168,7 +223,7 @@ describe('FormFieldModel', () => {
}); });
expect(field.hasEmptyValue).toBe(true); expect(field.hasEmptyValue).toBe(true);
expect(field.emptyOption).toEqual({ id: 'empty', name: 'Choose one...' }); expect(field.emptyValueOption).toEqual({ id: 'empty', name: 'Choose one...' });
expect(field.options).toEqual([ expect(field.options).toEqual([
{ id: 'empty', name: 'Choose one...' }, { id: 'empty', name: 'Choose one...' },
{ id: 'one', name: 'One' } { id: 'one', name: 'One' }
@ -495,7 +550,7 @@ describe('FormFieldModel', () => {
{ id: 'fake-option-2', name: 'fake label 2' }, { id: 'fake-option-2', name: 'fake label 2' },
{ id: 'fake-option-3', name: 'fake label 3' } { id: 'fake-option-3', name: 'fake label 3' }
], ],
value: 'fake-option-2' value: { id: 'fake-option-2', name: 'fake label 2' }
}); });
expect(field.getOptionName()).toBe('fake label 2'); expect(field.getOptionName()).toBe('fake label 2');
expect(field.hasEmptyValue).toBe(true); expect(field.hasEmptyValue).toBe(true);
@ -562,20 +617,17 @@ describe('FormFieldModel', () => {
expect(field.value).toBe(false); expect(field.value).toBe(false);
}); });
it('should set the value as null for a dropdown field that has the None value selected', () => { it('should set the form value as null for a dropdown field that has the "empty" option selected', () => {
const form = new FormModel(); const form = new FormModel();
const field = new FormFieldModel(form, { const field = new FormFieldModel(form, {
id: 'dropdown-1', id: 'dropdown-1',
type: FormFieldTypes.DROPDOWN type: FormFieldTypes.DROPDOWN,
options: [{ id: 'empty', name: 'Chose option...' }],
value: null
}); });
field.value = 'empty'; expect(field.hasEmptyValue).toBe(true);
expect(form.values['dropdown-1']).toBe(null); expect(field.value).toEqual({ id: 'empty', name: 'Chose option...' });
field.value = '';
expect(form.values['dropdown-1']).toBe(null);
field.value = undefined;
expect(form.values['dropdown-1']).toBe(null); expect(form.values['dropdown-1']).toBe(null);
}); });
@ -590,8 +642,12 @@ describe('FormFieldModel', () => {
] ]
}); });
field.value = 'opt2'; const valueBeforeSelection = form.values['dropdown-2'];
expect(form.values['dropdown-2']).toEqual(field.options[1]); field.value = field.options[1];
const valueAfterSelection = form.values['dropdown-2'];
expect(valueBeforeSelection).toEqual(null);
expect(valueAfterSelection).toEqual({ id: 'opt2', name: 'Option 2' });
}); });
it('should update form with radio button value', () => { it('should update form with radio button value', () => {
@ -728,7 +784,7 @@ describe('FormFieldModel', () => {
id: 'dropdown_field', id: 'dropdown_field',
name: 'header', name: 'header',
type: FormFieldTypes.DROPDOWN, type: FormFieldTypes.DROPDOWN,
value: 'opt1', value: { id: 'opt1', name: 'Option 1' },
required: false, required: false,
readOnly: true, readOnly: true,
options: [ options: [
@ -747,7 +803,7 @@ describe('FormFieldModel', () => {
id: 'dropdown_field', id: 'dropdown_field',
name: 'header', name: 'header',
type: FormFieldTypes.DROPDOWN, type: FormFieldTypes.DROPDOWN,
value: 'opt1', value: { id: 'opt1', name: 'Option 1' },
required: false, required: false,
readOnly: true, readOnly: true,
restUrl: 'fake-url-just-to-show', restUrl: 'fake-url-just-to-show',
@ -771,7 +827,7 @@ describe('FormFieldModel', () => {
id: 'dropdown_field', id: 'dropdown_field',
name: 'header', name: 'header',
type: FormFieldTypes.DROPDOWN, type: FormFieldTypes.DROPDOWN,
value: 'opt1', value: { id: 'opt1', name: 'Option 1' },
required: false, required: false,
readOnly: true, readOnly: true,
restUrl: 'fake-url-just-to-show', restUrl: 'fake-url-just-to-show',

View File

@ -38,6 +38,7 @@ export class FormFieldModel extends FormWidgetModel {
private _isValid: boolean = true; private _isValid: boolean = true;
private _required: boolean = false; private _required: boolean = false;
private readonly emptyValueOptionId = 'empty';
readonly defaultDateFormat: string = 'D-M-YYYY'; readonly defaultDateFormat: string = 'D-M-YYYY';
readonly defaultDateTimeFormat: string = 'D-M-YYYY hh:mm A'; readonly defaultDateTimeFormat: string = 'D-M-YYYY hh:mm A';
private readonly defaultEmptyOptionId = 'empty'; private readonly defaultEmptyOptionId = 'empty';
@ -96,7 +97,7 @@ export class FormFieldModel extends FormWidgetModel {
columns: ContainerColumnModel[] = []; columns: ContainerColumnModel[] = [];
// util members // util members
emptyOption: FormFieldOption; emptyValueOption: FormFieldOption;
validationSummary: ErrorMessageModel; validationSummary: ErrorMessageModel;
get value(): any { get value(): any {
@ -189,9 +190,9 @@ export class FormFieldModel extends FormWidgetModel {
this.maxDateRangeValue = json.maxDateRangeValue; this.maxDateRangeValue = json.maxDateRangeValue;
this.dynamicDateRangeSelection = json.dynamicDateRangeSelection; this.dynamicDateRangeSelection = json.dynamicDateRangeSelection;
this.regexPattern = json.regexPattern; this.regexPattern = json.regexPattern;
this.options = this.parseValidOptions(json.options); this.options = Array.isArray(json.options) ? json.options.filter((option) => this.isValidOption(option)) : [];
this.emptyOption = this.getEmptyOption(this.options); this.hasEmptyValue = json?.hasEmptyValue ?? this.hasEmptyValueOption(this.options);
this.hasEmptyValue = json?.hasEmptyValue ?? !!this.emptyOption; this.emptyValueOption = this.hasEmptyValue ? this.getEmptyValueOption(this.options) : undefined;
this.className = json.className; this.className = json.className;
this.optionType = json.optionType; this.optionType = json.optionType;
this.params = json.params || {}; this.params = json.params || {};
@ -236,8 +237,12 @@ export class FormFieldModel extends FormWidgetModel {
this.updateForm(); this.updateForm();
} }
private getEmptyOption(options: FormFieldOption[]): FormFieldOption { private getEmptyValueOption(options: FormFieldOption[]): FormFieldOption {
return options.find((option) => option?.id === this.defaultEmptyOptionId); return options.find((option) => option?.id === this.emptyValueOptionId);
}
private hasEmptyValueOption(options: FormFieldOption[]): boolean {
return options.some((option) => option?.id === this.emptyValueOptionId);
} }
private setValueForReadonlyType(form: any) { private setValueForReadonlyType(form: any) {
@ -304,41 +309,42 @@ export class FormFieldModel extends FormWidgetModel {
/* /*
This is needed due to Activiti issue related to reading dropdown values as value string This is needed due to Activiti issue related to reading dropdown values as value string
but saving back as object: { id: <id>, name: <name> } but saving back as object: { id: <id>, name: <name> }
Side note: Probably not valid anymore
*/ */
if (json.type === FormFieldTypes.DROPDOWN) { if (json.type === FormFieldTypes.DROPDOWN) {
if (this.hasEmptyValue) { if (this.hasEmptyValue && value === null) {
if (!this.emptyOption) { if (!this.emptyValueOption) {
this.emptyOption = { this.emptyValueOption = {
id: this.defaultEmptyOptionId, id: this.defaultEmptyOptionId,
name: this.defaultEmptyOptionName name: this.defaultEmptyOptionName
}; };
this.options.unshift(this.emptyOption); this.options.unshift(this.emptyValueOption);
} }
const isEmptyValue = !value || [this.emptyOption.id, this.emptyOption.name].includes(value); value = this.emptyValueOption;
if (isEmptyValue) { return value;
return this.emptyOption.id;
}
} }
if (this.isValidOption(value)) { if (this.isValidOption(value)) {
this.addOption(value); this.addOption(value);
return value.id; return value;
} }
if (this.hasMultipleValues) { if (this.hasMultipleValues) {
const validSelectedOptions = (Array.isArray(json.value) ? json.value : []).filter((option) => this.isValidOption(option)); let arrayOfSelectedOptions = Array.isArray(json.value) ? json.value : [];
arrayOfSelectedOptions = arrayOfSelectedOptions.filter((option) => this.isValidOption(option));
this.addOptions(validSelectedOptions); this.addOptions(arrayOfSelectedOptions);
return validSelectedOptions; value = arrayOfSelectedOptions;
return value;
} }
return null;
return value;
} }
/* /*
This is needed due to Activiti issue related to reading radio button values as value string This is needed due to Activiti issue related to reading radio button values as value string
but saving back as object: { id: <id>, name: <name> } but saving back as object: { id: <id>, name: <name> }
Side note: Probably not valid anymore
*/ */
if (json.type === FormFieldTypes.RADIO_BUTTONS) { if (json.type === FormFieldTypes.RADIO_BUTTONS) {
// Activiti has a bug with default radio button value where initial selection passed as `name` value // Activiti has a bug with default radio button value where initial selection passed as `name` value
@ -385,31 +391,7 @@ export class FormFieldModel extends FormWidgetModel {
switch (this.type) { switch (this.type) {
case FormFieldTypes.DROPDOWN: { case FormFieldTypes.DROPDOWN: {
if (!this.value) { this.form.values[this.id] = this.isEmptyValueOption(this.value) ? null : this.value;
this.form.values[this.id] = null;
break;
}
/*
This is needed due to Activiti reading dropdown values as string
but saving back as object: { id: <id>, name: <name> }
*/
if (Array.isArray(this.value)) {
this.form.values[this.id] = this.value;
break;
}
if (typeof this.value === 'string') {
if (this.value === 'empty' || this.value === '') {
this.form.values[this.id] = null;
break;
}
const entry: FormFieldOption[] = this.options.filter((opt) => opt.id === this.value);
if (entry.length > 0) {
this.form.values[this.id] = entry[0];
}
}
break; break;
} }
case FormFieldTypes.RADIO_BUTTONS: { case FormFieldTypes.RADIO_BUTTONS: {
@ -509,9 +491,8 @@ export class FormFieldModel extends FormWidgetModel {
return type === 'container'; return type === 'container';
} }
getOptionName(): string { getOptionName(): null | string {
const option: FormFieldOption = this.options.find((opt) => opt.id === this.value); return this.value ? this.value?.name : null;
return option ? option.name : null;
} }
hasOptions() { hasOptions() {
@ -519,7 +500,7 @@ export class FormFieldModel extends FormWidgetModel {
} }
isEmptyValueOption(option: FormFieldOption): boolean { isEmptyValueOption(option: FormFieldOption): boolean {
return this.hasEmptyValue && option?.id === this.defaultEmptyOptionId; return this.hasEmptyValueOption && option?.id === this.emptyValueOptionId;
} }
private addOptions(options: FormFieldOption[]) { private addOptions(options: FormFieldOption[]) {