mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-12 17:04:57 +00:00
[AAE-11480] - Fix required error is displayed for a non required drop… (#8021)
* [AAE-11480] - Fix required error is displayed for a non required dropdown * Use alias for async pipe instead of subscribing 2 times
This commit is contained in:
parent
e5489363a1
commit
e343de5c13
@ -531,7 +531,7 @@ describe('FormFieldModel', () => {
|
|||||||
expect(field.value).toBe(false);
|
expect(field.value).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should delete empty dropdown value from the form values', () => {
|
it('should set the value as null for a dropdown field that has the None value 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',
|
||||||
@ -539,10 +539,13 @@ describe('FormFieldModel', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
field.value = 'empty';
|
field.value = 'empty';
|
||||||
expect(form.values['dropdown-1']).toBe(undefined);
|
expect(form.values['dropdown-1']).toBe(null);
|
||||||
|
|
||||||
field.value = '';
|
field.value = '';
|
||||||
expect(form.values['dropdown-1']).toBe(undefined);
|
expect(form.values['dropdown-1']).toBe(null);
|
||||||
|
|
||||||
|
field.value = undefined;
|
||||||
|
expect(form.values['dropdown-1']).toBe(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update form with dropdown value', () => {
|
it('should update form with dropdown value', () => {
|
||||||
|
@ -361,6 +361,12 @@ 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] = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This is needed due to Activiti reading dropdown values as string
|
This is needed due to Activiti reading dropdown values as string
|
||||||
but saving back as object: { id: <id>, name: <name> }
|
but saving back as object: { id: <id>, name: <name> }
|
||||||
@ -372,7 +378,7 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
|
|
||||||
if (typeof this.value === 'string') {
|
if (typeof this.value === 'string') {
|
||||||
if (this.value === 'empty' || this.value === '') {
|
if (this.value === 'empty' || this.value === '') {
|
||||||
delete this.form.values[this.id];
|
this.form.values[this.id] = null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
|
<mat-label *ngIf="getDefaultOption(list$ | async) as defaultOption">
|
||||||
|
{{ defaultOption.name }}
|
||||||
|
</mat-label>
|
||||||
<mat-select class="adf-select"
|
<mat-select class="adf-select"
|
||||||
[id]="field.id"
|
[id]="field.id"
|
||||||
[(ngModel)]="field.value"
|
[(ngModel)]="field.value"
|
||||||
@ -21,7 +24,7 @@
|
|||||||
matTooltipShowDelay="1000"
|
matTooltipShowDelay="1000"
|
||||||
[multiple]="field.hasMultipleValues">
|
[multiple]="field.hasMultipleValues">
|
||||||
<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]="getOptionValue(opt, field.value)"
|
||||||
[id]="opt.id">{{opt.name}}
|
[id]="opt.id">{{opt.name}}
|
||||||
|
@ -232,6 +232,80 @@ describe('DropdownCloudWidgetComponent', () => {
|
|||||||
expect(options[0].nativeElement.innerText).toBe('default1_value');
|
expect(options[0].nativeElement.innerText).toBe('default1_value');
|
||||||
expect(widget.field.form.values['dropdown-id']).toEqual({ id: 'opt1', name: 'default1_value' });
|
expect(widget.field.form.values['dropdown-id']).toEqual({ id: 'opt1', name: 'default1_value' });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not display required error for a non required dropdown when selecting the none option', async () => {
|
||||||
|
widget.field.options = [
|
||||||
|
{ id: 'empty', name: 'Choose empty' },
|
||||||
|
...fakeOptionList
|
||||||
|
];
|
||||||
|
|
||||||
|
widget.ngOnInit();
|
||||||
|
fixture.detectChanges();
|
||||||
|
await openSelect();
|
||||||
|
|
||||||
|
const defaultOption: any = fixture.debugElement.query(By.css('[id="empty"]'));
|
||||||
|
widget.touched = true;
|
||||||
|
defaultOption.triggerEventHandler('click', null);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const requiredErrorElement = fixture.debugElement.query(By.css('.adf-dropdown-required-message .adf-error-text'));
|
||||||
|
expect(requiredErrorElement).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not display required error when selecting a valid option for a required dropdown', async () => {
|
||||||
|
widget.field.required = true;
|
||||||
|
widget.field.options = [
|
||||||
|
{ id: 'empty', name: 'Choose empty' },
|
||||||
|
...fakeOptionList
|
||||||
|
];
|
||||||
|
|
||||||
|
widget.ngOnInit();
|
||||||
|
fixture.detectChanges();
|
||||||
|
await openSelect();
|
||||||
|
|
||||||
|
const optionOne: any = fixture.debugElement.query(By.css('[id="opt_1"]'));
|
||||||
|
widget.touched = true;
|
||||||
|
optionOne.triggerEventHandler('click', null);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const requiredErrorElement = fixture.debugElement.query(By.css('.adf-dropdown-required-message .adf-error-text'));
|
||||||
|
expect(requiredErrorElement).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not have a value when switching from an available option to the None option', async () => {
|
||||||
|
widget.field.options = [
|
||||||
|
{ id: 'empty', name: 'This is a mock none option' },
|
||||||
|
...fakeOptionList
|
||||||
|
];
|
||||||
|
|
||||||
|
widget.ngOnInit();
|
||||||
|
fixture.detectChanges();
|
||||||
|
await openSelect();
|
||||||
|
|
||||||
|
const optionOne = fixture.debugElement.query(By.css('[id="opt_1"]'));
|
||||||
|
optionOne.triggerEventHandler('click', null);
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
let selectedValueElement = fixture.debugElement.query(By.css('.mat-select-value-text'));
|
||||||
|
|
||||||
|
expect(selectedValueElement.nativeElement.innerText).toEqual('option_1');
|
||||||
|
expect(widget.fieldValue).toEqual('opt_1');
|
||||||
|
|
||||||
|
await openSelect();
|
||||||
|
const defaultOption: any = fixture.debugElement.query(By.css('[id="empty"]'));
|
||||||
|
defaultOption.triggerEventHandler('click', null);
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
const dropdownLabel = fixture.debugElement.query(By.css('.adf-dropdown-widget mat-label'));
|
||||||
|
selectedValueElement = fixture.debugElement.query(By.css('.mat-select-value-text'));
|
||||||
|
|
||||||
|
expect(dropdownLabel.nativeNode.innerText).toEqual('This is a mock none option');
|
||||||
|
expect(widget.fieldValue).toEqual(undefined);
|
||||||
|
expect(selectedValueElement).toBeFalsy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when is required', () => {
|
describe('when is required', () => {
|
||||||
@ -253,7 +327,7 @@ describe('DropdownCloudWidgetComponent', () => {
|
|||||||
expect(asterisk.textContent).toEqual('*');
|
expect(asterisk.textContent).toEqual('*');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be invalid if no default option after interaction', async () => {
|
it('should display a required error when dropdown is required and has no value after an interaction', async () => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
|
|
||||||
@ -265,7 +339,8 @@ describe('DropdownCloudWidgetComponent', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
|
|
||||||
expect(element.querySelector('.adf-invalid')).toBeTruthy();
|
const requiredErrorElement = fixture.debugElement.query(By.css('.adf-dropdown-required-message .adf-error-text'));
|
||||||
|
expect(requiredErrorElement.nativeElement.innerText).toEqual('FORM.FIELD.REQUIRED');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -431,7 +506,7 @@ describe('DropdownCloudWidgetComponent', () => {
|
|||||||
|
|
||||||
it('should reset the options for a linked dropdown with restUrl when the parent dropdown selection changes to empty', async () => {
|
it('should reset the options for a linked dropdown with restUrl when the parent dropdown selection changes to empty', async () => {
|
||||||
widget.field.options = mockConditionalEntries[1].options;
|
widget.field.options = mockConditionalEntries[1].options;
|
||||||
parentDropdown.value = 'empty';
|
parentDropdown.value = undefined;
|
||||||
widget.selectionChangedForField(parentDropdown);
|
widget.selectionChangedForField(parentDropdown);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@ -439,7 +514,7 @@ describe('DropdownCloudWidgetComponent', () => {
|
|||||||
|
|
||||||
const defaultOption: any = fixture.debugElement.query(By.css('[id="empty"]'));
|
const defaultOption: any = fixture.debugElement.query(By.css('[id="empty"]'));
|
||||||
expect(widget.field.options).toEqual([{ id: 'empty', name: 'Choose one...' }]);
|
expect(widget.field.options).toEqual([{ id: 'empty', name: 'Choose one...' }]);
|
||||||
expect(defaultOption.context.value).toBe('empty');
|
expect(defaultOption.context.value).toBe(undefined);
|
||||||
expect(defaultOption.context.viewValue).toBe('Choose one...');
|
expect(defaultOption.context.viewValue).toBe('Choose one...');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -551,7 +626,7 @@ describe('DropdownCloudWidgetComponent', () => {
|
|||||||
const optThree: any = fixture.debugElement.query(By.css('[id="SKG"]'));
|
const optThree: any = fixture.debugElement.query(By.css('[id="SKG"]'));
|
||||||
|
|
||||||
expect(widget.field.options).toEqual(mockConditionalEntries[0].options);
|
expect(widget.field.options).toEqual(mockConditionalEntries[0].options);
|
||||||
expect(optOne.context.value).toBe('empty');
|
expect(optOne.context.value).toBe(undefined);
|
||||||
expect(optOne.context.viewValue).toBe('Choose one...');
|
expect(optOne.context.viewValue).toBe('Choose one...');
|
||||||
expect(optTwo.context.value).toBe('ATH');
|
expect(optTwo.context.value).toBe('ATH');
|
||||||
expect(optTwo.context.viewValue).toBe('Athens');
|
expect(optTwo.context.viewValue).toBe('Athens');
|
||||||
@ -561,7 +636,7 @@ describe('DropdownCloudWidgetComponent', () => {
|
|||||||
|
|
||||||
it('should reset the options for a linked dropdown when the parent dropdown selection changes to empty', async () => {
|
it('should reset the options for a linked dropdown when the parent dropdown selection changes to empty', async () => {
|
||||||
widget.field.options = mockConditionalEntries[1].options;
|
widget.field.options = mockConditionalEntries[1].options;
|
||||||
parentDropdown.value = 'empty';
|
parentDropdown.value = undefined;
|
||||||
widget.selectionChangedForField(parentDropdown);
|
widget.selectionChangedForField(parentDropdown);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@ -569,7 +644,7 @@ describe('DropdownCloudWidgetComponent', () => {
|
|||||||
|
|
||||||
const defaultOption: any = fixture.debugElement.query(By.css('[id="empty"]'));
|
const defaultOption: any = fixture.debugElement.query(By.css('[id="empty"]'));
|
||||||
expect(widget.field.options).toEqual([{ id: 'empty', name: 'Choose one...' }]);
|
expect(widget.field.options).toEqual([{ id: 'empty', name: 'Choose one...' }]);
|
||||||
expect(defaultOption.context.value).toBe('empty');
|
expect(defaultOption.context.value).toBe(undefined);
|
||||||
expect(defaultOption.context.viewValue).toBe('Choose one...');
|
expect(defaultOption.context.viewValue).toBe('Choose one...');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -134,9 +134,9 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
|
|||||||
}
|
}
|
||||||
|
|
||||||
private parentValueChanged(value: string) {
|
private parentValueChanged(value: string) {
|
||||||
if (value && !this.isDefaultValue(value)) {
|
if (value && !this.isNoneValueSelected(value)) {
|
||||||
this.isValidRestType() ? this.persistFieldOptionsFromRestApi() : this.persistFieldOptionsFromManualList(value);
|
this.isValidRestType() ? this.persistFieldOptionsFromRestApi() : this.persistFieldOptionsFromManualList(value);
|
||||||
} else if (this.isDefaultValue(value)) {
|
} else if (this.isNoneValueSelected(value)) {
|
||||||
this.resetRestApiErrorMessage();
|
this.resetRestApiErrorMessage();
|
||||||
this.addDefaultOption();
|
this.addDefaultOption();
|
||||||
this.resetInvalidValue();
|
this.resetInvalidValue();
|
||||||
@ -146,8 +146,8 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private isDefaultValue(value: string): boolean {
|
private isNoneValueSelected(value: string): boolean {
|
||||||
return value === DEFAULT_OPTION.id;
|
return value === undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getFormFieldById(fieldId): FormFieldModel {
|
private getFormFieldById(fieldId): FormFieldModel {
|
||||||
@ -181,7 +181,7 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
|
|||||||
}
|
}
|
||||||
|
|
||||||
private isValidValue(): boolean {
|
private isValidValue(): boolean {
|
||||||
return this.fieldValue && !this.isDefaultValue(this.fieldValue) && this.isSelectedValueInOptions();
|
return this.fieldValue && this.isSelectedValueInOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
private isSelectedValueInOptions(): boolean {
|
private isSelectedValueInOptions(): boolean {
|
||||||
@ -249,7 +249,9 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
|
|||||||
}
|
}
|
||||||
|
|
||||||
let optionValue: string = '';
|
let optionValue: string = '';
|
||||||
if (option.id === DEFAULT_OPTION.id || option.name !== fieldValue) {
|
if (option.id === DEFAULT_OPTION.id) {
|
||||||
|
optionValue = undefined;
|
||||||
|
} else if (option.name !== fieldValue) {
|
||||||
optionValue = option.id;
|
optionValue = option.id;
|
||||||
} else {
|
} else {
|
||||||
optionValue = option.name;
|
optionValue = option.name;
|
||||||
@ -309,6 +311,10 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
|
|||||||
}
|
}
|
||||||
|
|
||||||
showRequiredMessage(): boolean {
|
showRequiredMessage(): boolean {
|
||||||
return (this.isInvalidFieldRequired() || this.field.value === 'empty') && this.isTouched() && !this.isRestApiFailed;
|
return (this.isInvalidFieldRequired() || (this.isNoneValueSelected(this.field.value) && this.isRequired())) && this.isTouched() && !this.isRestApiFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDefaultOption(options: FormFieldOption[]): FormFieldOption {
|
||||||
|
return options.find((option: FormFieldOption) => option.id === DEFAULT_OPTION.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user