AAE-22947 Update dropdown-cloud.widget

This commit is contained in:
wiktord2000
2024-06-11 10:21:18 +02:00
parent 1773500d75
commit 727048a013
3 changed files with 66 additions and 70 deletions

View File

@@ -7,8 +7,8 @@
</div> </div>
<div> <div>
<mat-form-field> <mat-form-field>
<mat-label *ngIf="getDefaultOption(list$ | async) as defaultOption"> <mat-label *ngIf="getEmptyValueOption(list$ | async) as emptyValueOption">
{{ defaultOption.name }} {{ emptyValueOption.name }}
</mat-label> </mat-label>
<mat-select class="adf-select" <mat-select class="adf-select"
[id]="field.id" [id]="field.id"
@@ -26,7 +26,7 @@
<adf-select-filter-input *ngIf="showInputFilter" (change)="filter$.next($event)"></adf-select-filter-input> <adf-select-filter-input *ngIf="showInputFilter" (change)="filter$.next($event)"></adf-select-filter-input>
<mat-option *ngFor="let opt of list$ | async" <mat-option *ngFor="let opt of list$ | async"
[value]="getOptionValue(opt, field.value)" [value]="opt"
[id]="opt.id">{{opt.name}} [id]="opt.id">{{opt.name}}
</mat-option> </mat-option>
<mat-option id="readonlyOption" *ngIf="isReadOnlyType()" [value]="field.value">{{field.value}}</mat-option> <mat-option id="readonlyOption" *ngIf="isReadOnlyType()" [value]="field.value">{{field.value}}</mat-option>

View File

@@ -179,10 +179,10 @@ describe('DropdownCloudWidgetComponent', () => {
expect(await (await dropdown.getOptions())[0].getText()).toEqual('default1_value'); expect(await (await dropdown.getOptions())[0].getText()).toEqual('default1_value');
}); });
it('should preselect dropdown widget value when String (defined value) passed ', async () => { it('should preselect dropdown widget value when value matches one of the fetched options', async () => {
widget.field.restUrl = 'https://fake-rest-url'; widget.field.restUrl = 'https://fake-rest-url';
widget.field.optionType = 'rest'; widget.field.optionType = 'rest';
widget.field.value = 'opt1'; widget.field.value = { id: 'opt1', name: 'default1_value' };
spyOn(formCloudService, 'getRestWidgetData').and.returnValue( spyOn(formCloudService, 'getRestWidgetData').and.returnValue(
of([ of([
@@ -245,7 +245,7 @@ describe('DropdownCloudWidgetComponent', () => {
await dropdown.clickOptions({ selector: '[id="opt_1"]' }); await dropdown.clickOptions({ selector: '[id="opt_1"]' });
expect(await dropdown.getValueText()).toEqual('option_1'); expect(await dropdown.getValueText()).toEqual('option_1');
expect(widget.fieldValue).toEqual('opt_1'); expect(widget.fieldValue).toEqual({ id: 'opt_1', name: 'option_1' });
await dropdown.open(); await dropdown.open();
await dropdown.clickOptions({ selector: '[id="empty"]' }); await dropdown.clickOptions({ selector: '[id="empty"]' });
@@ -254,8 +254,8 @@ describe('DropdownCloudWidgetComponent', () => {
const dropdownLabel = await formField.getLabel(); const dropdownLabel = await formField.getLabel();
expect(dropdownLabel).toEqual('This is a mock none option'); expect(dropdownLabel).toEqual('This is a mock none option');
expect(widget.fieldValue).toEqual(undefined); expect(widget.fieldValue).toEqual({ id: 'empty', name: 'This is a mock none option' });
expect(await dropdown.getValueText()).toEqual(''); expect(await dropdown.getValueText()).toEqual('This is a mock none option');
}); });
}); });
@@ -344,6 +344,22 @@ describe('DropdownCloudWidgetComponent', () => {
}); });
}); });
it('should NOT display a required error when dropdown is readonly', async () => {
widget.field.readOnly = true;
fixture.detectChanges();
await fixture.whenStable();
expect(element.querySelector('.adf-invalid')).toBeFalsy();
const dropdownSelect = element.querySelector('.adf-select');
dropdownSelect.dispatchEvent(new Event('blur'));
fixture.detectChanges();
await fixture.whenStable();
expect(element.querySelector('.adf-invalid')).toBeFalsy();
});
describe('filter', () => { describe('filter', () => {
beforeEach(() => { beforeEach(() => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), { widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), {
@@ -432,7 +448,7 @@ describe('DropdownCloudWidgetComponent', () => {
}); });
it('should show preselected option for rest options', async () => { it('should show preselected option for rest options', async () => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: 'false' }), { widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), {
id: 'dropdown-id', id: 'dropdown-id',
name: 'date-name', name: 'date-name',
type: 'dropdown', type: 'dropdown',
@@ -471,7 +487,7 @@ describe('DropdownCloudWidgetComponent', () => {
}); });
it('should support multiple options for rest options', async () => { it('should support multiple options for rest options', async () => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: 'false' }), { widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), {
id: 'dropdown-id', id: 'dropdown-id',
name: 'date-name', name: 'date-name',
type: 'dropdown', type: 'dropdown',

View File

@@ -31,7 +31,7 @@ import { BehaviorSubject, combineLatest, Observable, of, Subject } from 'rxjs';
import { filter, map, takeUntil } from 'rxjs/operators'; import { filter, map, takeUntil } from 'rxjs/operators';
import { TaskVariableCloud } from '../../../models/task-variable-cloud.model'; import { TaskVariableCloud } from '../../../models/task-variable-cloud.model';
export const DEFAULT_OPTION = { export const DEFAULT_OPTION: FormFieldOption = {
id: 'empty', id: 'empty',
name: 'Choose one...' name: 'Choose one...'
}; };
@@ -218,16 +218,18 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
private buildBodyParam(): any { private buildBodyParam(): any {
const bodyParam = Object.assign({}); const bodyParam = Object.assign({});
if (this.isLinkedWidget()) { if (this.isLinkedWidget()) {
const parentWidgetValue = this.getParentWidgetValue(); const parentWidgetSelectedOption = this.getParentWidgetSelectedOption();
const parentWidgetSelectedOptionId = this.field.isEmptyValueOption(parentWidgetSelectedOption) ? null : parentWidgetSelectedOption.id;
const parentWidgetId = this.getLinkedWidgetId(); const parentWidgetId = this.getLinkedWidgetId();
bodyParam[parentWidgetId] = parentWidgetValue; bodyParam[parentWidgetId] = parentWidgetSelectedOptionId;
} }
return bodyParam; return bodyParam;
} }
private loadFieldOptionsForLinkedWidget() { private loadFieldOptionsForLinkedWidget() {
const parentWidgetValue = this.getParentWidgetValue(); const parentWidgetSelectedOption = this.getParentWidgetSelectedOption();
this.parentValueChanged(parentWidgetValue); this.parentValueChanged(parentWidgetSelectedOption);
this.formService.formFieldValueChanged this.formService.formFieldValueChanged
.pipe( .pipe(
@@ -240,16 +242,16 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
}); });
} }
private getParentWidgetValue(): string { private getParentWidgetSelectedOption(): FormFieldOption {
const parentWidgetId = this.getLinkedWidgetId(); const parentWidgetId = this.getLinkedWidgetId();
const parentWidget = this.getFormFieldById(parentWidgetId); const parentWidget = this.getFormFieldById(parentWidgetId);
return parentWidget?.value; return parentWidget?.value;
} }
private parentValueChanged(value: string) { private parentValueChanged(value: FormFieldOption) {
if (value && !this.isNoneValueSelected(value)) { if (value && !this.isEmptyValueOption(value)) {
this.isValidRestType() ? this.persistFieldOptionsFromRestApi() : this.persistFieldOptionsFromManualList(value); this.isValidRestType() ? this.persistFieldOptionsFromRestApi() : this.persistFieldOptionsFromManualList(value);
} else if (this.isNoneValueSelected(value)) { } else if (this.isEmptyValueOption(value)) {
this.resetRestApiErrorMessage(); this.resetRestApiErrorMessage();
this.resetOptions(); this.resetOptions();
this.resetInvalidValue(); this.resetInvalidValue();
@@ -259,19 +261,23 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
} }
} }
private isNoneValueSelected(value: string): boolean { private isEmptyValueOptionSelected(): boolean {
return value === undefined; return this.isEmptyValueOption(this.field.value);
}
private isEmptyValueOption(value: FormFieldOption): boolean {
return this.field.isEmptyValueOption(value);
} }
private getFormFieldById(fieldId): FormFieldModel { private getFormFieldById(fieldId): FormFieldModel {
return this.field.form.getFormFields().filter((field: FormFieldModel) => field.id === fieldId)[0]; return this.field.form.getFormFields().filter((field: FormFieldModel) => field.id === fieldId)[0];
} }
private persistFieldOptionsFromManualList(value: string) { private persistFieldOptionsFromManualList(option: FormFieldOption) {
if (this.hasRuleEntries()) { if (this.hasRuleEntries()) {
const rulesEntries = this.field.rule.entries; const rulesEntries = this.field.rule.entries;
rulesEntries.forEach((ruleEntry: RuleEntry) => { rulesEntries.forEach((ruleEntry: RuleEntry) => {
if (ruleEntry.key === value) { if (ruleEntry.key === option.id) {
this.field.options = ruleEntry.options; this.field.options = ruleEntry.options;
this.resetInvalidValue(); this.resetInvalidValue();
this.field.updateForm(); this.field.updateForm();
@@ -287,7 +293,7 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
} }
private resetValue() { private resetValue() {
this.field.value = ''; this.field.value = null;
this.selectionChangedForField(this.field); this.selectionChangedForField(this.field);
this.updateOptions(); this.updateOptions();
this.field.updateForm(); this.field.updateForm();
@@ -298,16 +304,15 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
} }
private isSelectedValueInOptions(): boolean { private isSelectedValueInOptions(): boolean {
if (Array.isArray(this.fieldValue)) { const selectedOptions: FormFieldOption[] = Array.isArray(this.fieldValue) ? this.fieldValue : [this.fieldValue];
const optionIdList = [...this.field.options].map((option) => option.id);
const fieldValueIds = this.fieldValue.map((valueOption) => valueOption.id); return selectedOptions.every((selectedOption) => {
return fieldValueIds.every((valueOptionId) => optionIdList.includes(valueOptionId)); const isIncludedInOptions = this.field.options.some((option) => option.id === selectedOption.id);
} else { return isIncludedInOptions;
return [...this.field.options].map((option) => option.id).includes(this.fieldValue); });
}
} }
get fieldValue(): string { get fieldValue(): FormFieldOption {
return this.field.value; return this.field.value;
} }
@@ -342,40 +347,12 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
return this.field?.rule?.ruleOn; return this.field?.rule?.ruleOn;
} }
compareDropdownValues(opt1: FormFieldOption | string, opt2: FormFieldOption | string): boolean { compareDropdownValues(opt1: FormFieldOption, opt2: FormFieldOption): boolean {
if (!opt1 || !opt2) { if (!opt1 || !opt2) {
return false; return false;
} }
if (typeof opt1 === 'string' && typeof opt2 === 'object') { return opt1.id === opt2.id && opt1.name === opt2.name;
return opt1 === opt2.id || opt1 === opt2.name;
}
if (typeof opt1 === 'object' && typeof opt2 === 'string') {
return opt1.id === opt2 || opt1.name === opt2;
}
if (typeof opt1 === 'object' && typeof opt2 === 'object') {
return opt1.id === opt2.id || opt1.name === opt2.name;
}
return opt1 === opt2;
}
getOptionValue(option: FormFieldOption, fieldValue: string): string | FormFieldOption {
if (this.field.hasMultipleValues) {
return option;
}
let optionValue: string = '';
if (option.id === DEFAULT_OPTION.id) {
optionValue = undefined;
} else if (option.name !== fieldValue) {
optionValue = option.id;
} else {
optionValue = option.name;
}
return optionValue;
} }
private isValidRestType(): boolean { private isValidRestType(): boolean {
@@ -404,11 +381,6 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
return this.field.type === 'readonly'; return this.field.type === 'readonly';
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
updateOptions(): void { updateOptions(): void {
if (this.isReadOnly()) { if (this.isReadOnly()) {
this.list$ = of(this.field.options); this.list$ = of(this.field.options);
@@ -448,14 +420,22 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
showRequiredMessage(): boolean { showRequiredMessage(): boolean {
return ( return (
(this.isInvalidFieldRequired() || (this.isNoneValueSelected(this.field.value) && this.isRequired())) && (this.isInvalidFieldRequired() || (this.isEmptyValueOptionSelected() && this.isRequired())) &&
this.isTouched() && this.isTouched() &&
!this.isRestApiFailed && !this.isRestApiFailed &&
!this.variableOptionsFailed !this.variableOptionsFailed
); );
} }
getDefaultOption(options: FormFieldOption[]): FormFieldOption { getEmptyValueOption(options: FormFieldOption[]): null | FormFieldOption {
return options.find((option: FormFieldOption) => option.id === DEFAULT_OPTION.id); if (!this.field.hasEmptyValue) {
return null;
}
return options.find((option: FormFieldOption) => this.field.isEmptyValueOption(option));
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
} }