AAE-40604 Fix for Dropdown required validation message is not present (#11600)

This commit is contained in:
Darren Thornton
2026-02-03 08:26:45 +00:00
committed by GitHub
parent 84de7c7765
commit 302b3e18ec
3 changed files with 84 additions and 23 deletions
@@ -4,11 +4,13 @@
[class.adf-readonly]="field.readOnly" [class.adf-readonly]="field.readOnly"
[class.adf-left-label-input-container]="field.leftLabels" [class.adf-left-label-input-container]="field.leftLabels"
> >
<div *ngIf="field.leftLabels"> @if(field.leftLabels) {
<div>
<label class="adf-label adf-left-label" [attr.for]="field.id"> <label class="adf-label adf-left-label" [attr.for]="field.id">
{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span> {{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
</label> </label>
</div> </div>
}
<div> <div>
<mat-form-field class="adf-form-field-input"> <mat-form-field class="adf-form-field-input">
@if ( (field.name || this.field?.required) && !field.leftLabels) { @if ( (field.name || this.field?.required) && !field.leftLabels) {
@@ -27,7 +29,9 @@
#select #select
(keydown.escape)="select.close()" (keydown.escape)="select.close()"
> >
<adf-select-filter-input *ngIf="showInputFilter" (change)="filter$.next($event)" /> @if(showInputFilter) {
<adf-select-filter-input (change)="filter$.next($event)" />
}
@for(opt of (list$ | async); track opt.id) { @for(opt of (list$ | async); track opt.id) {
<mat-option [value]="opt" [id]="opt.id"> <mat-option [value]="opt" [id]="opt.id">
@@ -48,19 +52,23 @@
<div <div
class="adf-error-messages-container" class="adf-error-messages-container"
[ngClass]="!previewState && !field.readOnly ? 'adf-error-messages-container-visible' : 'adf-error-messages-container-hidden'" [ngClass]="!field.readOnly ? 'adf-error-messages-container-visible' : 'adf-error-messages-container-hidden'"
> >
<error-widget class="adf-dropdown-required-message" *ngIf="showRequiredMessage" required="{{ 'FORM.FIELD.REQUIRED' | translate }}" /> @if(showRequiredMessage) {
<error-widget class="adf-dropdown-required-message" required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
}
@if(!previewState && isRestApiFailed) {
<error-widget <error-widget
class="adf-dropdown-failed-message" class="adf-dropdown-failed-message"
*ngIf="isRestApiFailed"
required="{{ 'FORM.FIELD.REST_API_FAILED' | translate: { hostname: restApiHostName } }}" required="{{ 'FORM.FIELD.REST_API_FAILED' | translate: { hostname: restApiHostName } }}"
/> />
}
@if(!previewState && variableOptionsFailed) {
<error-widget <error-widget
class="adf-dropdown-failed-message" class="adf-dropdown-failed-message"
*ngIf="variableOptionsFailed"
required="{{ 'FORM.FIELD.VARIABLE_DROPDOWN_OPTIONS_FAILED' | translate }}" required="{{ 'FORM.FIELD.VARIABLE_DROPDOWN_OPTIONS_FAILED' | translate }}"
/> />
}
</div> </div>
</div> </div>
</div> </div>
@@ -253,6 +253,24 @@ describe('DropdownCloudWidgetComponent', () => {
expect(widget.isRestApiFailed).toBe(true); expect(widget.isRestApiFailed).toBe(true);
expect(widget.field.options.length).toEqual(0); expect(widget.field.options.length).toEqual(0);
expect(errorMessageElement.nativeElement.textContent.trim()).toBe(errorIcon + 'FORM.FIELD.REST_API_FAILED'); expect(errorMessageElement.nativeElement.textContent.trim()).toBe(errorIcon + 'FORM.FIELD.REST_API_FAILED');
const errorsMessagesElement = fixture.debugElement.query(By.css('.adf-error-messages-container'));
expect(errorsMessagesElement.nativeElement.classList.contains('adf-error-messages-container-visible')).toBe(true);
});
it('should NOT show required message when REST API failed', () => {
widget.field.readOnly = false;
widget.field.required = true;
widget.ngOnInit();
widget.dropdownControl.markAsTouched();
fixture.detectChanges();
expect(widget.isRestApiFailed).toBe(true);
const requiredErrorElement = fixture.debugElement.query(By.css('.adf-dropdown-required-message .adf-error-text'));
expect(requiredErrorElement).toBeFalsy();
const restApiFailedElement = getErrorMessageElement();
expect(restApiFailedElement).toBeTruthy();
}); });
it('should NOT show error message when widget is readonly', async () => { it('should NOT show error message when widget is readonly', async () => {
@@ -268,6 +286,21 @@ describe('DropdownCloudWidgetComponent', () => {
const errorsMessagesElement = fixture.debugElement.query(By.css('.adf-error-messages-container')); const errorsMessagesElement = fixture.debugElement.query(By.css('.adf-error-messages-container'));
expect(errorsMessagesElement.nativeElement.classList.contains('adf-error-messages-container-hidden')).toBe(true); expect(errorsMessagesElement.nativeElement.classList.contains('adf-error-messages-container-hidden')).toBe(true);
}); });
it('should NOT show REST API failed error message when form is in preview state', () => {
widget.field.readOnly = false;
spyOn(formCloudService, 'getPreviewState').and.returnValue(true);
widget.ngOnInit();
fixture.detectChanges();
expect(getRestWidgetDataSpy).toHaveBeenCalled();
expect(widget.isRestApiFailed).toBe(true);
expect(widget.field.options.length).toEqual(0);
const failedErrorMsgElement = getErrorMessageElement();
expect(failedErrorMsgElement).toBeNull();
});
}); });
it('should preselect dropdown widget value when Json (rest call) passed', async () => { it('should preselect dropdown widget value when Json (rest call) passed', async () => {
@@ -405,6 +438,9 @@ describe('DropdownCloudWidgetComponent', () => {
expect(element.querySelector('.adf-invalid')).toBeTruthy(); expect(element.querySelector('.adf-invalid')).toBeTruthy();
const errorsMessagesElement = fixture.debugElement.query(By.css('.adf-error-messages-container'));
expect(errorsMessagesElement.nativeElement.classList.contains('adf-error-messages-container-visible')).toBe(true);
const requiredErrorElement = fixture.debugElement.query(By.css('.adf-dropdown-required-message .adf-error-text')); const requiredErrorElement = fixture.debugElement.query(By.css('.adf-dropdown-required-message .adf-error-text'));
expect(requiredErrorElement.nativeElement.innerText).toEqual('FORM.FIELD.REQUIRED'); expect(requiredErrorElement.nativeElement.innerText).toEqual('FORM.FIELD.REQUIRED');
}); });
@@ -1158,6 +1194,24 @@ describe('DropdownCloudWidgetComponent', () => {
checkDropdownVariableOptionsFailed(); checkDropdownVariableOptionsFailed();
}); });
it('should NOT show required message when variable options failed', () => {
widget.field = getVariableDropdownWidget(
'variables.json-variable',
'response.wrongPath.players',
'playerId',
'playerFullName',
mockProcessVariablesWithJson
);
widget.field.required = true;
fixture.detectChanges();
expect(widget.variableOptionsFailed).toBe(true);
const requiredErrorElement = fixture.debugElement.query(By.css('.adf-dropdown-required-message .adf-error-text'));
expect(requiredErrorElement).toBeFalsy();
const variableFailedElement = fixture.debugElement.query(By.css('.adf-dropdown-failed-message'));
expect(variableFailedElement).toBeTruthy();
});
it('should return empty array and display error when id is incorrect', () => { it('should return empty array and display error when id is incorrect', () => {
widget.field = getVariableDropdownWidget( widget.field = getVariableDropdownWidget(
'variables.json-variable', 'variables.json-variable',
@@ -1204,7 +1258,7 @@ describe('DropdownCloudWidgetComponent', () => {
checkDropdownVariableOptionsFailed(); checkDropdownVariableOptionsFailed();
}); });
it('should NOT display errors if form is in the preview state', () => { it('should NOT display variable options failed error when form is in the preview state', () => {
widget.field = getVariableDropdownWidget( widget.field = getVariableDropdownWidget(
'variables.json-variable', 'variables.json-variable',
'response.wrongPath.players', 'response.wrongPath.players',
@@ -1215,8 +1269,8 @@ describe('DropdownCloudWidgetComponent', () => {
spyOn(formCloudService, 'getPreviewState').and.returnValue(true); spyOn(formCloudService, 'getPreviewState').and.returnValue(true);
fixture.detectChanges(); fixture.detectChanges();
const errorsMessagesElement = fixture.debugElement.query(By.css('.adf-error-messages-container')); const failedErrorMsgElement = fixture.debugElement.query(By.css('.adf-dropdown-failed-message'));
expect(errorsMessagesElement.nativeElement.classList.contains('adf-error-messages-container-hidden')).toBe(true); expect(failedErrorMsgElement).toBeNull();
}); });
it('should NOT display errors if field is readonly', () => { it('should NOT display errors if field is readonly', () => {
@@ -29,7 +29,7 @@ import {
SelectFilterInputComponent, SelectFilterInputComponent,
WidgetComponent WidgetComponent
} from '@alfresco/adf-core'; } from '@alfresco/adf-core';
import { AsyncPipe, NgClass, NgIf } from '@angular/common'; import { AsyncPipe, NgClass } from '@angular/common';
import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core';
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
@@ -61,7 +61,6 @@ export const DROPDOWN_CLOUD_WIDGET_SET_VALUE_DEBOUNCE = 100;
}, },
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
imports: [ imports: [
NgIf,
NgClass, NgClass,
AsyncPipe, AsyncPipe,
ReactiveFormsModule, ReactiveFormsModule,