diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html
index 1a14469a2e0..2511a00ef9a 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html
@@ -1,14 +1,14 @@
- @if (!isCheckbox && hasLabel) {
+ [formGroup]="group"
+ [ngClass]="[getClass('element', 'container'), getClass('grid', 'container')]">
+ @if (!isCheckbox && hasLabel && !isDateField) {
+ [ngClass]="[getClass('element', 'label'), getClass('grid', 'label')]">
}
@@ -20,8 +20,7 @@
@if (hasHint && (formBuilderService.hasArrayGroupValue(model) || (!model.repeatable && (isRelationship === false || value?.value === null)) || (model.repeatable === true && context?.index === context?.context?.groups?.length - 1)) && (!showErrorMessages || errorMessages.length === 0)) {
-
+
}
@if (context?.parent?.groups?.length > 1 && (!showErrorMessages || errorMessages.length === 0)) {
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts
index b9335f20783..f4174827c46 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts
@@ -223,6 +223,8 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
testWSI.item = of(createSuccessfulRemoteDataObject(testItem));
const actions$: ReplaySubject = new ReplaySubject(1);
+ const renderer = jasmine.createSpyObj('Renderer2', ['setAttribute']);
+
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
@@ -286,6 +288,7 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
});
fixture.detectChanges();
+ renderer.setAttribute.calls.reset();
testElement = debugElement.query(By.css(`input[id='${testModel.id}']`));
}));
@@ -434,4 +437,43 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
});
});
+ it('should not show a label if is a checkbox or a date field', () => {
+ const checkboxLabel = fixture.debugElement.query(By.css('#label_' + formModel[0].id));
+ const dsDatePickerLabel = fixture.debugElement.query(By.css('#label_' + formModel[22].id));
+
+ expect(checkboxLabel).toBeNull();
+ expect(dsDatePickerLabel).toBeNull();
+ });
+
+ it('should not call handleAriaLabelForLibraryComponents if is SSR', () => {
+ (component as any).platformId = 'server';
+ (component as any).componentRef = {
+ instance: new DynamicNGBootstrapInputComponent(null, null),
+ location: { nativeElement: document.createElement('div') },
+ } as any;
+ fixture.detectChanges();
+
+ (component as any).handleAriaLabelForLibraryComponents();
+
+ expect(renderer.setAttribute).not.toHaveBeenCalled();
+ });
+
+ it('should set aria-label when valid input and additional property ariaLabel exist and is on browser', () => {
+ (component as any).platformId = 'browser';
+ const inputEl = document.createElement('input');
+ const hostEl = {
+ querySelector: jasmine.createSpy('querySelector').and.returnValue(inputEl),
+ };
+
+ (component as any).componentRef = {
+ instance: new DynamicNGBootstrapInputComponent(null, null),
+ location: { nativeElement: hostEl },
+ } as any;
+ (component as any).renderer = renderer;
+ component.model = { additional: { ariaLabel: 'Accessible Label' } } as any;
+ fixture.detectChanges();
+ (component as any).handleAriaLabelForLibraryComponents();
+ expect(renderer.setAttribute).toHaveBeenCalledWith(inputEl, 'aria-label', 'Accessible Label');
+ });
+
});
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts
index 534300b55df..3e239ce2844 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts
@@ -1,5 +1,6 @@
import {
AsyncPipe,
+ isPlatformBrowser,
NgClass,
NgTemplateOutlet,
} from '@angular/common';
@@ -19,7 +20,9 @@ import {
OnDestroy,
OnInit,
Output,
+ PLATFORM_ID,
QueryList,
+ Renderer2,
SimpleChanges,
Type,
ViewChild,
@@ -40,10 +43,12 @@ import {
import {
DYNAMIC_FORM_CONTROL_MAP_FN,
DYNAMIC_FORM_CONTROL_TYPE_CHECKBOX,
+ DynamicFormArrayComponent,
DynamicFormArrayGroupModel,
DynamicFormArrayModel,
DynamicFormComponentService,
DynamicFormControl,
+ DynamicFormControlComponent,
DynamicFormControlContainerComponent,
DynamicFormControlEvent,
DynamicFormControlEventType,
@@ -130,6 +135,7 @@ import {
} from './existing-metadata-list-element/existing-metadata-list-element.component';
import { ExistingRelationListElementComponent } from './existing-relation-list-element/existing-relation-list-element.component';
import { DYNAMIC_FORM_CONTROL_TYPE_CUSTOM_SWITCH } from './models/custom-switch/custom-switch.model';
+import { DYNAMIC_FORM_CONTROL_TYPE_DSDATEPICKER } from './models/date-picker/date-picker.model';
import { DsDynamicLookupRelationModalComponent } from './relation-lookup-modal/dynamic-lookup-relation-modal.component';
@Component({
@@ -223,6 +229,8 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
@Inject(APP_CONFIG) protected appConfig: AppConfig,
@Inject(DYNAMIC_FORM_CONTROL_MAP_FN) protected dynamicFormControlFn: DynamicFormControlMapFn,
private actions$: Actions,
+ protected renderer: Renderer2,
+ @Inject(PLATFORM_ID) protected platformId: string,
) {
super(ref, componentFactoryResolver, layoutService, validationService, dynamicFormComponentService, relationService);
this.fetchThumbnail = this.appConfig.browseBy.showThumbnails;
@@ -324,6 +332,10 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
return this.model.type === DYNAMIC_FORM_CONTROL_TYPE_CHECKBOX || this.model.type === DYNAMIC_FORM_CONTROL_TYPE_CUSTOM_SWITCH;
}
+ get isDateField(): boolean {
+ return this.model.type === DYNAMIC_FORM_CONTROL_TYPE_DSDATEPICKER;
+ }
+
ngOnChanges(changes: SimpleChanges) {
if (changes && !this.isRelationship && hasValue(this.group.get(this.model.id))) {
super.ngOnChanges(changes);
@@ -345,6 +357,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
ngAfterViewInit() {
this.showErrorMessagesPreviousStage = this.showErrorMessages;
+ this.handleAriaLabelForLibraryComponents();
}
protected createFormControlComponent(): void {
@@ -516,4 +529,22 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
this.subs.push(collection$.subscribe((collection) => this.collection = collection));
}
+
+ private handleAriaLabelForLibraryComponents(): void {
+ if (!isPlatformBrowser(this.platformId)) {
+ return;
+ }
+
+ if ((this.componentRef.instance instanceof DynamicFormControlComponent) &&
+ !(this.componentRef.instance instanceof DynamicFormArrayComponent) &&
+ this.componentRef.location.nativeElement) {
+ const inputEl: HTMLElement | null =
+ this.componentRef.location.nativeElement.querySelector('input,textarea,select,[role="textbox"]');
+
+
+ if (inputEl && this.model?.additional?.ariaLabel) {
+ this.renderer.setAttribute(inputEl, 'aria-label', this.model.additional.ariaLabel);
+ }
+ }
+ }
}
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html
index 5d38f9e9084..3e6e05c7f74 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html
@@ -2,12 +2,12 @@