Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[class.d-none]="model.hidden"
[formGroup]="group"
[ngClass]="[getClass('element', 'container'), getClass('grid', 'container')]">
<label *ngIf="!isCheckbox && hasLabel"
<label *ngIf="!isCheckbox && hasLabel && !isDateField"
[id]="'label_' + model.id"
[for]="id"
[innerHTML]="(model.required && model.label) ? (model.label | translate) + ' *' : (model.label | translate)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,10 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
let testElement: DebugElement;
const testItem: Item = new Item();
const testWSI: WorkspaceItem = new WorkspaceItem();
testWSI.item = observableOf(createSuccessfulRemoteDataObject(testItem));
const actions$: ReplaySubject<any> = new ReplaySubject<any>(1);
testWSI.item = observableOf(createSuccessfulRemoteDataObject(testItem));
const renderer = jasmine.createSpyObj('Renderer2', ['setAttribute']);

beforeEach(waitForAsync(() => {

TestBed.configureTestingModule({
Expand Down Expand Up @@ -286,6 +288,7 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
});

fixture.detectChanges();
renderer.setAttribute.calls.reset();
testElement = debugElement.query(By.css(`input[id='${testModel.id}']`));
}));

Expand Down Expand Up @@ -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');
});

});
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
AsyncPipe,
isPlatformBrowser,
NgClass,
NgForOf,
NgIf,
Expand All @@ -21,7 +22,9 @@ import {
OnDestroy,
OnInit,
Output,
PLATFORM_ID,
QueryList,
Renderer2,
SimpleChanges,
Type,
ViewChild,
Expand All @@ -42,10 +45,12 @@ import {
import {
DYNAMIC_FORM_CONTROL_MAP_FN,
DYNAMIC_FORM_CONTROL_TYPE_CHECKBOX,
DynamicFormArrayComponent,
DynamicFormArrayGroupModel,
DynamicFormArrayModel,
DynamicFormComponentService,
DynamicFormControl,
DynamicFormControlComponent,
DynamicFormControlContainerComponent,
DynamicFormControlEvent,
DynamicFormControlEventType,
Expand Down Expand Up @@ -108,7 +113,6 @@ import { SubmissionObjectDataService } from '../../../../core/submission/submiss
import { paginatedRelationsToItems } from '../../../../item-page/simple/item-types/shared/item-relationships-utils';
import { SubmissionObjectActionTypes } from '../../../../submission/objects/submission-objects.actions';
import { SubmissionService } from '../../../../submission/submission.service';
import { BtnDisabledDirective } from '../../../btn-disabled.directive';
import {
hasNoValue,
hasValue,
Expand All @@ -132,6 +136,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({
Expand All @@ -151,7 +156,6 @@ import { DsDynamicLookupRelationModalComponent } from './relation-lookup-modal/d
NgbTooltipModule,
NgTemplateOutlet,
ExistingRelationListElementComponent,
BtnDisabledDirective,
],
standalone: true,
})
Expand Down Expand Up @@ -229,6 +233,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;
Expand Down Expand Up @@ -330,6 +336,11 @@ 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);
Expand All @@ -351,6 +362,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo

ngAfterViewInit() {
this.showErrorMessagesPreviousStage = this.showErrorMessages;
this.handleAriaLabelForLibraryComponents();
}

protected createFormControlComponent(): void {
Expand Down Expand Up @@ -522,4 +534,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);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<div>
<fieldset class="d-flex justify-content-start flex-wrap gap-2">
<legend *ngIf="!model.repeatable" [id]="'legend_' + model.id" [ngClass]="[getClass('element', 'label'), getClass('grid', 'label')]">
{{model.placeholder}} <span *ngIf="model.required">*</span>
</legend>
{{model.label}} <span *ngIf="model.required">*</span>
</legend>
<ds-number-picker
tabindex="0"
[id]="model.id + '_year'"
Expand All @@ -15,7 +15,7 @@
[value]="year"
[invalid]="showErrorMessages"
[placeholder]="'form.date-picker.placeholder.year' | translate"
[widthClass]="'four-digits'"
[widthClass]="'four-digits'"
(blur)="onBlur($event)"
(change)="onChange($event)"
(focus)="onFocus($event)"
Expand All @@ -27,12 +27,12 @@
[min]="minMonth"
[max]="maxMonth"
[name]="'month'"
[size]="2"
[size]="2"
[(ngModel)]="initialMonth"
[value]="month"
[placeholder]="'form.date-picker.placeholder.month' | translate"
[disabled]="!year || model.disabled"
[widthClass]="'two-digits'"
[widthClass]="'two-digits'"
(blur)="onBlur($event)"
(change)="onChange($event)"
(focus)="onFocus($event)"
Expand All @@ -49,7 +49,7 @@
[value]="day"
[placeholder]="'form.date-picker.placeholder.day' | translate"
[disabled]="!month || model.disabled"
[widthClass]="'two-digits'"
[widthClass]="'two-digits'"
(blur)="onBlur($event)"
(change)="onChange($event)"
(focus)="onFocus($event)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
class="form-control"
[attr.aria-labelledby]="'label_' + model.id"
[attr.autoComplete]="model.autoComplete"
[attr.aria-label]="model.label | translate"
[attr.aria-label]="(model.label || model?.additional?.ariaLabel) | translate"
[class.is-invalid]="showErrorMessages"
[id]="model.id"
[inputFormatter]="formatter"
Expand All @@ -59,7 +59,7 @@
<input class="form-control"
[attr.aria-labelledby]="'label_' + model.id"
[attr.autoComplete]="model.autoComplete"
[attr.aria-label]="model.label | translate"
[attr.aria-label]="(model.label || model?.additional?.ariaLabel) | translate"
[class.is-invalid]="showErrorMessages"
[class.tree-input]="!model.readOnly"
[id]="id"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
aria-hidden="true"></i>
<input class="form-control"
[attr.aria-controls]="'combobox_' + id + '_listbox'"
[attr.aria-label]="model.placeholder"
[attr.aria-label]="model.label"
[attr.autoComplete]="model.autoComplete"
[class.is-invalid]="showErrorMessages"
[class.scrollable-dropdown-input]="!model.readOnly"
Expand All @@ -29,11 +29,11 @@

<div #dropdownMenu ngbDropdownMenu
class="dropdown-menu scrollable-dropdown-menu w-100"
[attr.aria-label]="model.placeholder">
[attr.aria-label]="model.label">
<div class="scrollable-menu"
role="listbox"
[id]="'combobox_' + id + '_listbox'"
[attr.aria-label]="model.placeholder"
[attr.aria-label]="model.label"
infiniteScroll
[infiniteScrollDistance]="2"
[infiniteScrollThrottle]="50"
Expand Down
8 changes: 4 additions & 4 deletions src/app/shared/form/builder/parsers/concat-field-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,18 +92,18 @@ export class ConcatFieldParser extends FieldParser {
concatGroup.disabled = input1ModelConfig.readOnly;

if (isNotEmpty(this.firstPlaceholder)) {
input1ModelConfig.placeholder = this.firstPlaceholder;
input1ModelConfig.label = this.firstPlaceholder;
}

if (isNotEmpty(this.secondPlaceholder)) {
input2ModelConfig.placeholder = this.secondPlaceholder;
input2ModelConfig.label = this.secondPlaceholder;
}

// Split placeholder if is like 'placeholder1/placeholder2'
const placeholder = this.configData.label.split('/');
if (placeholder.length === 2) {
input1ModelConfig.placeholder = placeholder[0];
input2ModelConfig.placeholder = placeholder[1];
input1ModelConfig.label = placeholder[0];
input2ModelConfig.label = placeholder[1];
}

const model1 = new DsDynamicInputModel(input1ModelConfig, clsInput);
Expand Down
7 changes: 7 additions & 0 deletions src/app/shared/form/builder/parsers/date-field-parser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,11 @@ describe('DateFieldParser test suite', () => {

expect(fieldModel.value).toEqual(expectedValue);
});

it('should skip setting the placeholder', () => {
const parser = new DateFieldParser(submissionId, field, initFormValues, parserOptions, translateService);
const fieldModel = parser.parse();

expect(fieldModel.placeholder).toBeNull();
});
});
4 changes: 2 additions & 2 deletions src/app/shared/form/builder/parsers/date-field-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ export class DateFieldParser extends FieldParser {

public modelFactory(fieldValue?: FormFieldMetadataValueObject, label?: boolean): any {
let malformedDate = false;
const inputDateModelConfig: DynamicDsDateControlModelConfig = this.initModel(null, false, true);
inputDateModelConfig.legend = this.configData.label;
const inputDateModelConfig: DynamicDsDateControlModelConfig = this.initModel(null, label, true);
inputDateModelConfig.legend = this.configData.repeatable ? null : this.configData.label;
inputDateModelConfig.disabled = inputDateModelConfig.readOnly;
inputDateModelConfig.toggleIcon = 'fas fa-calendar';
this.setValues(inputDateModelConfig as any, fieldValue);
Expand Down
3 changes: 2 additions & 1 deletion src/app/shared/form/builder/parsers/field-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,8 @@ export abstract class FieldParser {
if (hint) {
controlModel.hint = this.configData.hints || '&nbsp;';
}
controlModel.placeholder = this.configData.label;

controlModel.additional = { ...controlModel.additional, ariaLabel: this.configData.label };

if (this.configData.mandatory && setErrors) {
this.markAsRequired(controlModel);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
[readonly]="disabled"
[disabled]="disabled"
[ngClass]="{'is-invalid': invalid}"
placeholder="{{'form.number-picker.label.' + placeholder | translate }}"
title="{{'form.number-picker.label.' + placeholder | translate}}"
[attr.aria-labelledby]="id + ' increment-' + id + ' decrement-' + id"
>
Expand Down
Loading