Skip to content

Commit bdf5037

Browse files
[DURACOM-347] refactor, fix missing label for library components
1 parent cb7f454 commit bdf5037

9 files changed

Lines changed: 73 additions & 10 deletions

config/config.example.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ submission:
240240
# If set to true avoid setting placeholder for simple fields, where the placeholder would be the same as the label.
241241
# The default is set to true as placeholders that do not provide additional information to the field are to be avoided as they could cause accessibility issue.
242242
# More info on the topic can be found at https://www.deque.com/blog/accessible-forms-the-problem-with-placeholders/
243-
ignorePlaceholderForSimpleFields:
243+
omitSimpleFieldPlaceholders:
244244

245245

246246
# Fallback language in which the UI will be rendered if the user's browser language is not an active language

src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
223223
testWSI.item = of(createSuccessfulRemoteDataObject(testItem));
224224
const actions$: ReplaySubject<any> = new ReplaySubject<any>(1);
225225

226+
const renderer = jasmine.createSpyObj('Renderer2', ['setAttribute']);
227+
226228
beforeEach(waitForAsync(() => {
227229

228230
TestBed.configureTestingModule({
@@ -442,4 +444,35 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
442444
expect(dsDatePickerLabel).toBeNull();
443445
});
444446

447+
it('should not call handleAriaLabelForLibraryComponents if is SSR', () => {
448+
(component as any).platformId = 'server';
449+
(component as any).componentRef = {
450+
instance: new DynamicNGBootstrapInputComponent(null, null),
451+
location: { nativeElement: document.createElement('div') },
452+
} as any;
453+
fixture.detectChanges();
454+
455+
(component as any).handleAriaLabelForLibraryComponents();
456+
457+
expect(renderer.setAttribute).not.toHaveBeenCalled();
458+
});
459+
460+
it('should set aria-label when valid input and additional property ariaLabel exist and is on browser', () => {
461+
(component as any).platformId = 'browser';
462+
const inputEl = document.createElement('input');
463+
const hostEl = {
464+
querySelector: jasmine.createSpy('querySelector').and.returnValue(inputEl),
465+
};
466+
467+
(component as any).componentRef = {
468+
instance: new DynamicNGBootstrapInputComponent(null, null),
469+
location: { nativeElement: hostEl },
470+
} as any;
471+
(component as any).renderer = renderer;
472+
component.model = { additional: { ariaLabel: 'Accessible Label' } } as any;
473+
fixture.detectChanges();
474+
(component as any).handleAriaLabelForLibraryComponents();
475+
expect(renderer.setAttribute).toHaveBeenCalledWith(inputEl, 'aria-label', 'Accessible Label');
476+
});
477+
445478
});

src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
AsyncPipe,
3+
isPlatformBrowser,
34
NgClass,
45
NgTemplateOutlet,
56
} from '@angular/common';
@@ -19,7 +20,9 @@ import {
1920
OnDestroy,
2021
OnInit,
2122
Output,
23+
PLATFORM_ID,
2224
QueryList,
25+
Renderer2,
2326
SimpleChanges,
2427
Type,
2528
ViewChild,
@@ -44,6 +47,7 @@ import {
4447
DynamicFormArrayModel,
4548
DynamicFormComponentService,
4649
DynamicFormControl,
50+
DynamicFormControlComponent,
4751
DynamicFormControlContainerComponent,
4852
DynamicFormControlEvent,
4953
DynamicFormControlEventType,
@@ -129,8 +133,10 @@ import {
129133
ReorderableRelationship,
130134
} from './existing-metadata-list-element/existing-metadata-list-element.component';
131135
import { ExistingRelationListElementComponent } from './existing-relation-list-element/existing-relation-list-element.component';
136+
import { DsDynamicFormArrayComponent } from './models/array-group/dynamic-form-array.component';
132137
import { DYNAMIC_FORM_CONTROL_TYPE_CUSTOM_SWITCH } from './models/custom-switch/custom-switch.model';
133138
import { DsDynamicLookupRelationModalComponent } from './relation-lookup-modal/dynamic-lookup-relation-modal.component';
139+
import { DsDynamicFormGroupComponent } from './models/form-group/dynamic-form-group.component';
134140

135141
@Component({
136142
selector: 'ds-dynamic-form-control-container',
@@ -223,6 +229,8 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
223229
@Inject(APP_CONFIG) protected appConfig: AppConfig,
224230
@Inject(DYNAMIC_FORM_CONTROL_MAP_FN) protected dynamicFormControlFn: DynamicFormControlMapFn,
225231
private actions$: Actions,
232+
protected renderer: Renderer2,
233+
@Inject(PLATFORM_ID) protected platformId: string,
226234
) {
227235
super(ref, componentFactoryResolver, layoutService, validationService, dynamicFormComponentService, relationService);
228236
this.fetchThumbnail = this.appConfig.browseBy.showThumbnails;
@@ -349,6 +357,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
349357

350358
ngAfterViewInit() {
351359
this.showErrorMessagesPreviousStage = this.showErrorMessages;
360+
this.handleAriaLabelForLibraryComponents();
352361
}
353362

354363
protected createFormControlComponent(): void {
@@ -520,4 +529,23 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
520529
this.subs.push(collection$.subscribe((collection) => this.collection = collection));
521530

522531
}
532+
533+
private handleAriaLabelForLibraryComponents(): void {
534+
if (!isPlatformBrowser(this.platformId)) {
535+
return;
536+
}
537+
538+
if ((this.componentRef.instance instanceof DynamicFormControlComponent) &&
539+
!(this.componentRef.instance instanceof DsDynamicFormArrayComponent) &&
540+
!(this.componentRef.instance instanceof DsDynamicFormGroupComponent) &&
541+
this.componentRef.location.nativeElement) {
542+
const inputEl: HTMLElement | null =
543+
this.componentRef.location.nativeElement.querySelector('input,textarea,select,[role="textbox"]');
544+
545+
546+
if (inputEl && this.model?.additional?.ariaLabel) {
547+
this.renderer.setAttribute(inputEl, 'aria-label', this.model.additional.ariaLabel);
548+
}
549+
}
550+
}
523551
}

src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
class="form-control"
4242
[attr.aria-labelledby]="'label_' + model.id"
4343
[attr.autoComplete]="model.autoComplete"
44-
[attr.aria-label]="model.label | translate"
44+
[attr.aria-label]="(model.label || model?.additional?.ariaLabel) | translate"
4545
[class.is-invalid]="showErrorMessages"
4646
[id]="model.id"
4747
[inputFormatter]="formatter"

src/app/shared/form/builder/parsers/date-field-parser.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ describe('DateFieldParser test suite', () => {
6868
expect(fieldModel.value).toEqual(expectedValue);
6969
});
7070

71-
it('should skip setting the placeholder when ignore ignorePlaceholderForSimpleFields is true', () => {
71+
it('should skip setting the placeholder when ignore omitSimpleFieldPlaceholders is true', () => {
7272
const parser = new DateFieldParser(submissionId, field, initFormValues, parserOptions, translateService);
73-
parser.ignorePlaceholderForSimpleFields = true;
73+
parser.omitSimpleFieldPlaceholders = true;
7474
const fieldModel = parser.parse();
7575

7676
expect(fieldModel.placeholder).toBeNull();

src/app/shared/form/builder/parsers/field-parser.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export abstract class FieldParser {
5454
*/
5555
protected typeField: string;
5656

57-
ignorePlaceholderForSimpleFields: boolean;
57+
omitSimpleFieldPlaceholders: boolean;
5858

5959
constructor(
6060
@Inject(SUBMISSION_ID) protected submissionId: string,
@@ -63,7 +63,7 @@ export abstract class FieldParser {
6363
@Inject(PARSER_OPTIONS) protected parserOptions: ParserOptions,
6464
protected translate: TranslateService,
6565
) {
66-
this.ignorePlaceholderForSimpleFields = environment.submission.ignorePlaceholderForSimpleFields;
66+
this.omitSimpleFieldPlaceholders = environment.submission.omitSimpleFieldPlaceholders;
6767
}
6868

6969
public abstract modelFactory(fieldValue?: FormFieldMetadataValueObject, label?: boolean): any;
@@ -310,8 +310,10 @@ export abstract class FieldParser {
310310
if (hint) {
311311
controlModel.hint = this.configData.hints || '&nbsp;';
312312
}
313-
if (!this.ignorePlaceholderForSimpleFields) {
313+
if (!this.omitSimpleFieldPlaceholders) {
314314
controlModel.placeholder = this.configData.label;
315+
} else {
316+
controlModel.additional = { ...controlModel.additional, ariaLabel: this.configData.label };
315317
}
316318

317319
if (this.configData.mandatory && setErrors) {

src/config/default-app-config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ export class DefaultAppConfig implements AppConfig {
254254
],
255255
},
256256
},
257-
ignorePlaceholderForSimpleFields: true,
257+
omitSimpleFieldPlaceholders: true,
258258
};
259259

260260
// Fallback language in which the UI will be rendered if the user's browser language is not an active language

src/config/submission-config.interface.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,5 @@ export interface SubmissionConfig extends Config {
3636
duplicateDetection: DuplicateDetectionConfig;
3737
typeBind: TypeBindConfig;
3838
icons: IconsConfig;
39-
ignorePlaceholderForSimpleFields?: boolean;
39+
omitSimpleFieldPlaceholders?: boolean;
4040
}

src/environments/environment.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ export const environment: BuildConfig = {
195195
],
196196
},
197197
},
198-
ignorePlaceholderForSimpleFields: false,
198+
omitSimpleFieldPlaceholders: false,
199199
},
200200

201201
// NOTE: will log all redux actions and transfers in console

0 commit comments

Comments
 (0)