Skip to content

Commit e1865a6

Browse files
committed
feat(ngx-table): Make the table accessible through the tree-grid pattern
1 parent 81c6bfb commit e1865a6

File tree

18 files changed

+1003
-288
lines changed

18 files changed

+1003
-288
lines changed

apps/table-test/src/app/app.component.html

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
[data]="data | async"
1919
[columns]="columns"
2020
[selectable]="true"
21+
[currentSorting]="currentSort"
2122
selectableKey="id"
2223
[resetFormOnNewData]="false"
2324
(rowClicked)="rowEmitted($event)"
@@ -38,14 +39,26 @@
3839
</ng-template>
3940
}
4041

41-
<ngx-table-cell column="firstName" [cypressDataTags]="{ cell: 'cell-tag' }">
42+
<ngx-table-cell
43+
column="firstName"
44+
[cypressDataTags]="{ cell: 'cell-tag' }"
45+
[sortable]="true"
46+
(sort)="sort($event)"
47+
>
4248
<ng-template #headerTmpl> First name </ng-template>
4349
</ngx-table-cell>
4450

45-
<ngx-currency-table-cell column="amount" currency="EUR">
51+
<ngx-currency-table-cell column="amount" currency="EUR" [editable]="true">
4652
<ng-template #headerTmpl> Amount </ng-template>
4753
</ngx-currency-table-cell>
4854

55+
<ngx-table-cell column="button">
56+
<ng-template #cellTmpl>
57+
<button>Button 1</button>
58+
<button>Button 2</button>
59+
</ng-template>
60+
</ngx-table-cell>
61+
4962
<ng-template #loadingTmpl> Loading </ng-template>
5063
</ngx-table>
5164

apps/table-test/src/app/app.component.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms';
33
import { BehaviorSubject } from 'rxjs';
44
import { AsyncPipe, JsonPipe } from '@angular/common';
55
import { WrapperComponent } from './wrapper/wrapper.component';
6-
import { NgxCurrencyTableCellComponent, NgxTable } from '@ngx/table';
6+
import { NgxCurrencyTableCellComponent, NgxTable, NgxTableSortEvent } from '@ngx/table';
77

88
@Component({
99
selector: 'app-root',
@@ -21,6 +21,7 @@ import { NgxCurrencyTableCellComponent, NgxTable } from '@ngx/table';
2121
})
2222
export class AppComponent {
2323
private currentSet = 'dataSet1';
24+
public currentSort: NgxTableSortEvent;
2425

2526
public dataSet1 = [
2627
{
@@ -39,6 +40,14 @@ export class AppComponent {
3940
hello: 'world',
4041
amount: 5000,
4142
},
43+
{
44+
name: 'Hyperdrive',
45+
firstName: 'Studio',
46+
active: true,
47+
id: 'SHD2',
48+
hello: 'world',
49+
amount: 5000,
50+
},
4251
];
4352

4453
public dataSet2 = [
@@ -54,7 +63,7 @@ export class AppComponent {
5463

5564
public data = new BehaviorSubject(this.dataSet1);
5665

57-
public readonly columns = ['firstName', 'name', 'amount', 'active'];
66+
public readonly columns = ['firstName', 'name', 'button', 'amount', 'active'];
5867

5968
public showDetail = true;
6069

@@ -85,4 +94,8 @@ export class AppComponent {
8594
public rowEmitted(data: any) {
8695
console.log(data);
8796
}
97+
98+
public sort(event: NgxTableSortEvent) {
99+
this.currentSort = event;
100+
}
88101
}

libs/table/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,10 @@ If you wish to provide a custom class to the row of your tables, you can provide
385385

386386
Cells can also have a default class we want to provide to all cells of that kind. All `ngx-date-table-cell` cells have the `ngx-date-table-cell` class and the same applies for the `ngx-currency-table-cell`.
387387

388+
### Accessibility
389+
390+
`ngx-table` provides a WCAG and ARIA compliant implementation to tables. When a table has a detail row or is selectable, the role of the table switches from `table` to `treegrid`. Because of that, `ngx-table` follows the [WAI ARIA Treegrid Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/treegrid/).
391+
388392
## Acknowledgements
389393

390394
A big thanks goes out to [Sam Verschueren](https://github.com/SamVerschueren) for his help with the initial implementation of this table. Without his help, this table would not have existed.

libs/table/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@
99
"angular cdk",
1010
"cdk",
1111
"table",
12-
"detail row"
12+
"detail row",
13+
"wai",
14+
"aria",
15+
"wcag",
16+
"treegrid"
1317
],
1418
"homepage": "https://github.com/studiohyperdrive/ngx-tools/tree/master/libs/table",
1519
"author": {

libs/table/src/lib/cell/cell.directive.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,23 @@ import { NgxTableCypressDataTags, NgxTableSortEvent } from '../interfaces';
88
standalone: true,
99
})
1010
export class NgxAbstractTableCellDirective {
11+
/**
12+
* The current sortDirection of the cell
13+
*/
14+
public sortDirection: NgxTableSortDirection | null = null;
15+
16+
/**
17+
* The templates used to set in the table
18+
*/
19+
public footerTemplate: TemplateRef<any>;
20+
public headerTemplate: TemplateRef<any>;
21+
public cellTemplate: TemplateRef<any>;
22+
23+
/**
24+
* An optional class that can be set for the cell
25+
*/
26+
public cellClass: string;
27+
1128
/**
1229
* The name of the column we want this cell to represent
1330
*/
@@ -24,24 +41,15 @@ export class NgxAbstractTableCellDirective {
2441
*/
2542
@Input() public cypressDataTags: NgxTableCypressDataTags;
2643

27-
@Output() sort = new EventEmitter<NgxTableSortEvent>();
28-
2944
/**
30-
* The current sortDirection of the cell
45+
* Whether the content of a cell is editable. By default, this is set to false
3146
*/
32-
public sortDirection: NgxTableSortDirection | null = null;
47+
@Input() public editable: boolean = false;
3348

3449
/**
35-
* The templates used to set in the table
50+
* Emits the sortable event if a column is sortable
3651
*/
37-
public footerTemplate: TemplateRef<any>;
38-
public headerTemplate: TemplateRef<any>;
39-
public cellTemplate: TemplateRef<any>;
40-
41-
/**
42-
* An optional class that can be set for the cell
43-
*/
44-
public cellClass: string;
52+
@Output() sort = new EventEmitter<NgxTableSortEvent>();
4553

4654
/**
4755
* Handles the sorting click events
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { Directive, HostListener } from '@angular/core';
2+
3+
/**
4+
* An abstract directive used as a base to handle focussed base actions
5+
*/
6+
@Directive({
7+
standalone: true,
8+
})
9+
export abstract class NgxHasFocusDirective {
10+
/**
11+
* Whether the current element is focussed
12+
*/
13+
protected hasFocus: boolean = false;
14+
15+
/**
16+
* Set the hasFocus flag
17+
*/
18+
@HostListener('focus') setFocus() {
19+
this.hasFocus = true;
20+
}
21+
22+
/**
23+
* Remove the hasFocus flag
24+
*/
25+
@HostListener('blur') removeFocus() {
26+
this.hasFocus = false;
27+
}
28+
29+
/**
30+
* Execute an action when the element has focussed
31+
*
32+
* @param action - The provided action
33+
*/
34+
public handleWhenFocussed(action: () => void): void {
35+
if (this.hasFocus) {
36+
action();
37+
}
38+
}
39+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './has-focus.directive';
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './has-focus-action';
2+
export * from './tree-grid';
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { NgxTreeGridRowDirective } from './tree-grid-row.directive';
2+
import { NgxTreeGridCellDirective } from './tree-grid.cell.directive';
3+
import { NgxTreeGridDirective } from './tree-grid.directive';
4+
5+
export const NgxTreeGrid = [
6+
NgxTreeGridDirective,
7+
NgxTreeGridRowDirective,
8+
NgxTreeGridCellDirective,
9+
];

0 commit comments

Comments
 (0)