diff --git a/lib/core/src/lib/datatable/components/datatable/datatable.component.html b/lib/core/src/lib/datatable/components/datatable/datatable.component.html
index ea030262ed..6751cf639a 100644
--- a/lib/core/src/lib/datatable/components/datatable/datatable.component.html
+++ b/lib/core/src/lib/datatable/components/datatable/datatable.component.html
@@ -53,12 +53,8 @@
'adf-datatable__header--sorted-asc': isColumnSorted(col, 'asc'),
'adf-datatable__header--sorted-desc': isColumnSorted(col, 'desc')}"
[ngStyle]="(col.width) && !lastColumn && {'flex': getFlexValue(col)}"
- [attr.aria-label]="col.srTitle ? (col.srTitle | translate) : (col.title | translate) + (col.subtitle ? ' ' + (col.subtitle | translate) : '')"
- (click)="onColumnHeaderClick(col, $event)"
- (keyup.enter)="onColumnHeaderClick(col, $event)"
role="columnheader"
- [attr.tabindex]="col.sortable ? 0 : null"
- [attr.aria-sort]="col.sortable ? (getAriaSort(col) | translate) : null"
+ [attr.aria-sort]="col.sortable ? getAriaSort(col) : null"
cdkDrag
cdkDragLockAxis="x"
(cdkDragStarted)="isDraggingHeaderColumn = true"
@@ -73,6 +69,21 @@
+
+ {{ getSortLiveAnnouncement(col) | translate: { string: col.title | translate } }}
+
+
-
- {{ getSortLiveAnnouncement(col) | translate: { string: col.title | translate } }}
-
-
diff --git a/lib/core/src/lib/datatable/components/datatable/datatable.component.spec.ts b/lib/core/src/lib/datatable/components/datatable/datatable.component.spec.ts
index 8beedf4913..d9862c6bfe 100644
--- a/lib/core/src/lib/datatable/components/datatable/datatable.component.spec.ts
+++ b/lib/core/src/lib/datatable/components/datatable/datatable.component.spec.ts
@@ -440,6 +440,20 @@ describe('DataTable', () => {
);
});
+ it('should fallback to column sortingKey if key is missing', () => {
+ const sorting = new DataSorting('displayName', 'asc');
+ dataTable.data = new ObjectDataTableAdapter([{ name: '1' }, { name: '2' }], [new ObjectDataColumn({ key: 'name' })]);
+ dataTable.data.setSorting(sorting);
+
+ const column1 = new ObjectDataColumn({ key: 'name', sortable: true, direction: 'desc', sortingKey: 'displayName' });
+ const column2 = new ObjectDataColumn({ key: 'displayName', sortable: true, direction: 'desc', sortingKey: 'name' });
+ const column3 = new ObjectDataColumn({ key: 'other', sortable: true, direction: 'desc', sortingKey: 'other' });
+
+ expect(dataTable.isColumnSortActive(column1)).toBeTrue();
+ expect(dataTable.isColumnSortActive(column2)).toBeTrue();
+ expect(dataTable.isColumnSortActive(column3)).toBeFalse();
+ });
+
it('should change the rows on changing of the data', () => {
const newData = new ObjectDataTableAdapter([{ name: 'TEST' }, { name: 'FAKE' }], [new ObjectDataColumn({ key: 'name' })]);
dataTable.data = new ObjectDataTableAdapter([{ name: '1' }, { name: '2' }], [new ObjectDataColumn({ key: 'name' })]);
@@ -1588,6 +1602,27 @@ describe('Accessibility', () => {
let columnCustomTemplate: TemplateRef
;
let testingUtils: UnitTestingUtils;
+ const setupAndCheckHeaderColumns = (sortable: boolean, selector: string, assertions: (element: DebugElement | null) => void) => {
+ dataTable.showHeader = ShowHeaderMode.Always;
+ const dataRows = [{ name: 'name1' }];
+
+ dataTable.data = new ObjectDataTableAdapter([], [new ObjectDataColumn({ key: 'name', template: columnCustomTemplate, sortable })]);
+
+ dataTable.ngOnChanges({
+ rows: new SimpleChange(null, dataRows, false)
+ });
+
+ fixture.detectChanges();
+ dataTable.ngAfterViewInit();
+
+ const element = testingUtils.getByCSS(selector);
+ assertions(element);
+ };
+
+ const headerCellSelector = '.adf-datatable-cell-header';
+ const bodyCellSelector = '.adf-datatable-cell';
+ const headerCellContentSelector = '.adf-datatable-cell-header-content';
+
const focusTrapFactory = jasmine.createSpyObj('ConfigurableFocusTrapFactory', ['create']);
const focusTrap = jasmine.createSpyObj('ConfigurableFocusTrap', ['focusInitialElement', 'destroy']);
@@ -1638,25 +1673,25 @@ describe('Accessibility', () => {
column = new ObjectDataColumn({ key: 'key' });
});
- it('should return correct translation key when no sort is applied', () => {
+ it('should return correct key without translation when no sort is applied', () => {
spyOn(dataTable, 'isColumnSortActive').and.returnValue(false);
- expect(dataTable.getAriaSort(column)).toBe('ADF-DATATABLE.ACCESSIBILITY.SORT_NONE');
+ expect(dataTable.getAriaSort(column)).toBe('none');
});
- it('should return translation key when column sort is ascending', () => {
+ it('should return key without translation when column sort is ascending', () => {
const isColumnSortedAsc = true;
spyOn(dataTable, 'isColumnSortActive').and.returnValue(true);
spyOn(dataTable, 'isColumnSorted').and.returnValue(isColumnSortedAsc);
- expect(dataTable.getAriaSort(column)).toBe('ADF-DATATABLE.ACCESSIBILITY.SORT_ASCENDING');
+ expect(dataTable.getAriaSort(column)).toBe('ascending');
});
- it('should return translation key when column sort is descending', () => {
+ it('should return key without translation when column sort is descending', () => {
const isColumnSortedAsc = false;
spyOn(dataTable, 'isColumnSortActive').and.returnValue(true);
spyOn(dataTable, 'isColumnSorted').and.returnValue(isColumnSortedAsc);
- expect(dataTable.getAriaSort(column)).toBe('ADF-DATATABLE.ACCESSIBILITY.SORT_DESCENDING');
+ expect(dataTable.getAriaSort(column)).toBe('descending');
});
});
@@ -1716,41 +1751,68 @@ describe('Accessibility', () => {
});
describe('Row cells focus management', () => {
- const testFocus = (sortable: boolean, selector: string, expectedTabindex: string | null) => {
- dataTable.showHeader = ShowHeaderMode.Always;
- const dataRows = [{ name: 'name1' }];
-
- dataTable.data = new ObjectDataTableAdapter([], [new ObjectDataColumn({ key: 'name', template: columnCustomTemplate, sortable })]);
-
- dataTable.ngOnChanges({
- rows: new SimpleChange(null, dataRows, false)
- });
-
- fixture.detectChanges();
- dataTable.ngAfterViewInit();
-
- const element = testingUtils.getByCSS(selector);
- expect(element?.nativeElement.getAttribute('tabindex')).toEqual(expectedTabindex);
- };
-
- const headerCellSelector = '.adf-datatable-cell-header';
-
it('should remove header cell focus when cell is not sortable', () => {
- testFocus(false, headerCellSelector, null);
+ setupAndCheckHeaderColumns(false, headerCellSelector, (element) => {
+ expect(element?.nativeElement.getAttribute('tabindex')).toBeNull();
+ });
});
it('should allow header cell focus when cell is sortable', () => {
- testFocus(true, headerCellSelector, '0');
+ setupAndCheckHeaderColumns(true, headerCellSelector, (element) => {
+ expect(element?.nativeElement.getAttribute('tabindex')).toBeNull();
+ });
});
it('should set tabindex equal to null on body cell by default (sortable = false)', () => {
- const bodyCellSelector = '.adf-datatable-cell';
- testFocus(false, bodyCellSelector, null);
+ setupAndCheckHeaderColumns(false, bodyCellSelector, (element) => {
+ expect(element?.nativeElement.getAttribute('tabindex')).toBeNull();
+ });
});
it('should set tabindex equal to null on body cell by default (sortable = true)', () => {
- const bodyCellSelector = '.adf-datatable-cell';
- testFocus(true, bodyCellSelector, null);
+ setupAndCheckHeaderColumns(true, bodyCellSelector, (element) => {
+ expect(element?.nativeElement.getAttribute('tabindex')).toBeNull();
+ });
+ });
+
+ it('should set tabindex equal to 0 on header cell sortable wrapper when cell is sortable', () => {
+ setupAndCheckHeaderColumns(true, headerCellContentSelector, (element) => {
+ expect(element?.nativeElement.getAttribute('tabindex')).toBe('0');
+ });
+ });
+
+ it('should set tabindex equal to null on header cell sortable wrapper when cell is not sortable', () => {
+ setupAndCheckHeaderColumns(false, headerCellContentSelector, (element) => {
+ expect(element?.nativeElement.getAttribute('tabindex')).toBeNull();
+ });
+ });
+ });
+
+ it('should set role="button" on sortable header content cells', () => {
+ setupAndCheckHeaderColumns(true, headerCellContentSelector, (element) => {
+ expect(element?.nativeElement.getAttribute('role')).toEqual('button');
+ });
+ });
+
+ it('should have no role set on non-sortable header content cells', () => {
+ setupAndCheckHeaderColumns(false, headerCellContentSelector, (element) => {
+ expect(element?.nativeElement.getAttribute('role')).toBeNull();
+ });
+ });
+
+ it('should set aria-description on an active sortable header content cells', () => {
+ spyOn(dataTable, 'isColumnSortActive').and.returnValue(true);
+
+ setupAndCheckHeaderColumns(true, headerCellContentSelector, (element) => {
+ expect(element?.nativeElement.getAttribute('aria-description')).toBeDefined();
+ });
+ });
+
+ it('should not set aria-description on non-active sortable header content cells', () => {
+ spyOn(dataTable, 'isColumnSortActive').and.returnValue(false);
+
+ setupAndCheckHeaderColumns(true, headerCellContentSelector, (element) => {
+ expect(element?.nativeElement.getAttribute('aria-description')).toBeNull();
});
});
diff --git a/lib/core/src/lib/datatable/components/datatable/datatable.component.ts b/lib/core/src/lib/datatable/components/datatable/datatable.component.ts
index d73d66a8fa..b2e435374e 100644
--- a/lib/core/src/lib/datatable/components/datatable/datatable.component.ts
+++ b/lib/core/src/lib/datatable/components/datatable/datatable.component.ts
@@ -452,10 +452,11 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
}
isColumnSortActive(column: DataColumn): boolean {
- if (!column || !this.data.getSorting()) {
+ const sorting = this.data.getSorting();
+ if (!column || !sorting) {
return false;
}
- return column.key === this.data.getSorting().key;
+ return column.key === sorting.key || column.sortingKey === sorting.key;
}
getVisibleColumns(): DataColumn[] {
@@ -747,7 +748,7 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
private isValidClickEvent(event: Event): boolean {
if (event instanceof MouseEvent) {
- return event.eventPhase === event.BUBBLING_PHASE;
+ return event.eventPhase === event.AT_TARGET || event.eventPhase === event.BUBBLING_PHASE;
} else if (event instanceof KeyboardEvent) {
return event.eventPhase === event.AT_TARGET;
}
@@ -1031,10 +1032,10 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
getAriaSort(column: DataColumn): string {
if (!this.isColumnSortActive(column)) {
- return 'ADF-DATATABLE.ACCESSIBILITY.SORT_NONE';
+ return 'none';
}
- return this.isColumnSorted(column, 'asc') ? 'ADF-DATATABLE.ACCESSIBILITY.SORT_ASCENDING' : 'ADF-DATATABLE.ACCESSIBILITY.SORT_DESCENDING';
+ return this.isColumnSorted(column, 'asc') ? 'ascending' : 'descending';
}
getSortLiveAnnouncement(column: DataColumn): string {