From e98fd2db0c4dd3127ef5251a77e840677bd0a971 Mon Sep 17 00:00:00 2001 From: arditdomi <32884230+arditdomi@users.noreply.github.com> Date: Mon, 24 Jan 2022 13:57:22 +0000 Subject: [PATCH] [AAE-7010] - Fix nested linked dropdowns are not reset (#7463) * [AAE-7010] - Fix nested linked dropdowns are not reset * Rebase * Reset rest in case value is not part of the options * Update failing unit test due to form field changes --- .../widgets/core/form-field.model.spec.ts | 6 +- .../widgets/core/form-field.model.ts | 21 +++--- .../dropdown/dropdown-cloud.widget.spec.ts | 64 ++++++++++++++++++- .../widgets/dropdown/dropdown-cloud.widget.ts | 42 +++++++++--- 4 files changed, 108 insertions(+), 25 deletions(-) diff --git a/lib/core/form/components/widgets/core/form-field.model.spec.ts b/lib/core/form/components/widgets/core/form-field.model.spec.ts index 8b28bb8b7fd..32cac3f8479 100644 --- a/lib/core/form/components/widgets/core/form-field.model.spec.ts +++ b/lib/core/form/components/widgets/core/form-field.model.spec.ts @@ -531,7 +531,7 @@ describe('FormFieldModel', () => { expect(field.value).toBe(false); }); - it('should update form with empty dropdown value', () => { + it('should delete empty dropdown value from the form values', () => { const form = new FormModel(); const field = new FormFieldModel(form, { id: 'dropdown-1', @@ -539,10 +539,10 @@ describe('FormFieldModel', () => { }); field.value = 'empty'; - expect(form.values['dropdown-1']).toEqual({}); + expect(form.values['dropdown-1']).toBe(undefined); field.value = ''; - expect(form.values['dropdown-1']).toEqual({}); + expect(form.values['dropdown-1']).toBe(undefined); }); it('should update form with dropdown value', () => { diff --git a/lib/core/form/components/widgets/core/form-field.model.ts b/lib/core/form/components/widgets/core/form-field.model.ts index 098190e30da..f91448343c6 100644 --- a/lib/core/form/components/widgets/core/form-field.model.ts +++ b/lib/core/form/components/widgets/core/form-field.model.ts @@ -293,17 +293,14 @@ export class FormFieldModel extends FormWidgetModel { if (json.type === FormFieldTypes.DROPDOWN) { if (json.options) { - const options = json.options || []; - if (options.length > 0) { - if (json.hasEmptyValue) { - const emptyOption = json.options[0]; - if (value === '' || value === emptyOption.id || value === emptyOption.name) { - value = emptyOption.id; - } - } else { - if (value?.id && value?.name) { - value = value.id; - } + if (json.hasEmptyValue) { + const emptyOption = json.options[0]; + if (value === '' || value === emptyOption.id || value === emptyOption.name) { + value = emptyOption.id; + } + } else { + if (value?.id && value?.name) { + value = value.id; } } } @@ -371,7 +368,7 @@ export class FormFieldModel extends FormWidgetModel { if (typeof this.value === 'string') { if (this.value === 'empty' || this.value === '') { - this.form.values[this.id] = {}; + delete this.form.values[this.id]; break; } diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.spec.ts b/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.spec.ts index 408d8411ec7..71f1f8566e3 100644 --- a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.spec.ts +++ b/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.spec.ts @@ -19,7 +19,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { of, throwError } from 'rxjs'; import { DropdownCloudWidgetComponent } from './dropdown-cloud.widget'; -import { FormFieldModel, FormModel, FormService, setupTestBed } from '@alfresco/adf-core'; +import { FormFieldModel, FormModel, FormService, setupTestBed, FormFieldEvent } from '@alfresco/adf-core'; import { FormCloudService } from '../../../services/form-cloud.service'; import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module'; import { TranslateModule } from '@ngx-translate/core'; @@ -428,6 +428,25 @@ describe('DropdownCloudWidgetComponent', () => { expect(widget.field.options.length).toBe(2); expect(failedErrorMsgElement3).toBeNull(); }); + + describe('Rest - On parent value changes (chain)', () => { + it('should fire a form field value changed event when the value gets reset (notify children on the chain to reset)', () => { + spyOn(formCloudService, 'getRestWidgetData').and.returnValue(throwError('Failed to fetch options')); + widget.field.options = mockConditionalEntries[1].options; + widget.field.value = 'MI'; + fixture.detectChanges(); + + const formFieldValueChangedSpy = spyOn(formService.formFieldValueChanged, 'next').and.callThrough(); + const formFieldValueChangedEvent = new FormFieldEvent(widget.field.form, widget.field); + + parentDropdown.value = 'GR'; + widget.selectionChangedForField(parentDropdown); + fixture.detectChanges(); + + expect(formFieldValueChangedSpy).toHaveBeenCalledWith(formFieldValueChangedEvent); + expect(widget.field.options).toEqual([]); + }); + }); }); describe('Manual options', () => { @@ -480,6 +499,49 @@ describe('DropdownCloudWidgetComponent', () => { expect(defaultOption.context.value).toBe('empty'); expect(defaultOption.context.viewValue).toBe('Choose one...'); }); + + describe('Manual - On parent value changes (chain)', () => { + it('should reset the current value when it not part of the available options', () => { + widget.field.options = mockConditionalEntries[1].options; + widget.field.value = 'non-existent-value'; + fixture.detectChanges(); + + parentDropdown.value = 'GR'; + widget.selectionChangedForField(parentDropdown); + fixture.detectChanges(); + + expect(widget.field.options).toEqual(mockConditionalEntries[0].options); + expect(widget.fieldValue).toEqual(''); + }); + + it('should not reset the current value when it is part of the available options', () => { + widget.field.options = mockConditionalEntries[1].options; + widget.field.value = 'ATH'; + fixture.detectChanges(); + + parentDropdown.value = 'GR'; + widget.selectionChangedForField(parentDropdown); + fixture.detectChanges(); + + expect(widget.field.options).toEqual(mockConditionalEntries[0].options); + expect(widget.fieldValue).toEqual('ATH'); + }); + + it('should fire a form field value changed event when the value gets reset (notify children on the chain to reset)', () => { + widget.field.options = mockConditionalEntries[1].options; + widget.field.value = 'non-existent-value'; + fixture.detectChanges(); + + const formFieldValueChangedSpy = spyOn(formService.formFieldValueChanged, 'next').and.callThrough(); + const formFieldValueChangedEvent = new FormFieldEvent(widget.field.form, widget.field); + + parentDropdown.value = 'GR'; + widget.selectionChangedForField(parentDropdown); + fixture.detectChanges(); + + expect(formFieldValueChangedSpy).toHaveBeenCalledWith(formFieldValueChangedEvent); + }); + }); }); describe('Load selection for linked dropdown (i.e. saved, completed forms)', () => { diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.ts b/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.ts index d28b7c4ac50..4bea68f0b39 100644 --- a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.ts +++ b/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.ts @@ -104,6 +104,7 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI this.field.options = result; this.updateOptions(); this.field.updateForm(); + this.resetInvalidValue(); }, (err) => { this.resetRestApiOptions(); this.handleError(err); @@ -133,18 +134,18 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI } private parentValueChanged(value: string) { - if (this.isValidValue(value)) { + if (value && !this.isDefaultValue(value)) { this.isValidRestType() ? this.persistFieldOptionsFromRestApi() : this.persistFieldOptionsFromManualList(value); } else if (this.isDefaultValue(value)) { this.resetRestApiErrorMessage(); this.addDefaultOption(); + this.resetInvalidValue(); + } else { + this.field.options = []; + this.resetInvalidValue(); } } - private isValidValue(value: string): boolean { - return !!value && value !== DropdownCloudWidgetComponent.DEFAULT_OPTION.id; - } - private isDefaultValue(value: string): boolean { return value === DropdownCloudWidgetComponent.DEFAULT_OPTION.id; } @@ -159,13 +160,37 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI rulesEntries.forEach((ruleEntry: RuleEntry) => { if (ruleEntry.key === value) { this.field.options = ruleEntry.options; - this.updateOptions(); - this.field.updateForm(); + this.resetInvalidValue(); } }); } } + private resetInvalidValue() { + if (!this.isValidValue()) { + this.resetValue(); + } + } + + private resetValue() { + this.field.value = ''; + this.selectionChangedForField(this.field); + this.updateOptions(); + this.field.updateForm(); + } + + private isValidValue(): boolean { + return this.fieldValue && !this.isDefaultValue(this.fieldValue) && this.isSelectedValueInOptions(); + } + + private isSelectedValueInOptions(): boolean { + return [...this.field.options].map(option => option.id).includes(this.fieldValue); + } + + get fieldValue(): string { + return this.field.value; + } + private hasRuleEntries(): boolean { return !!this.field.rule.entries.length; } @@ -269,10 +294,9 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI resetRestApiOptions() { this.field.options = []; + this.resetValue(); this.isRestApiFailed = true; this.restApiHostName = this.getRestUrlHostName(); - this.updateOptions(); - this.field.updateForm(); } private getRestUrlHostName(): string {