Skip to content

Commit cc31280

Browse files
authoredApr 5, 2021
feat(ui5-table): Introduce Single and Multi selection (#2848)
Support single, multi selection modes in ui5-table component. FIXES: #2659
1 parent 0a4758b commit cc31280

21 files changed

+1400
-43
lines changed
 

‎packages/main/src/Table.hbs

+12-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,18 @@
55

66
<table border="0" cellspacing="0" cellpadding="0" @keydown="{{_onkeydown}}" role="table">
77
<thead>
8-
<tr id="{{_columnHeader.id}}" role="row" class="ui5-table-header-row" tabindex="{{_columnHeader._tabIndex}}" style="height: 48px" @click="{{_onColumnHeaderClick}}">
8+
<tr id="{{_columnHeader.id}}" role="row" class="ui5-table-header-row" aria-label="{{ariaLabelText}}" tabindex="{{_columnHeader._tabIndex}}" style="height: 48px" @click="{{_onColumnHeaderClick}}">
9+
{{#if isMultiSelect}}
10+
<th class="ui5-table-select-all-column" role="presentation" aria-hidden="true">
11+
<ui5-checkbox class="ui5-table-select-all-checkbox"
12+
?checked="{{_allRowsSelected}}"
13+
@ui5-change="{{_selectAll}}"
14+
aria-label="{{ariaLabelSelectAllText}}"
15+
>
16+
</ui5-checkbox>
17+
</th>
18+
{{/if}}
19+
920
{{#each visibleColumns}}
1021
<slot name="{{this._individualSlot}}"></slot>
1122
{{/each}}

‎packages/main/src/Table.js

+154-4
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,14 @@ import debounce from "@ui5/webcomponents-base/dist/util/debounce.js";
1010
import isElementInView from "@ui5/webcomponents-base/dist/util/isElementInView.js";
1111
import TableGrowingMode from "./types/TableGrowingMode.js";
1212
import BusyIndicator from "./BusyIndicator.js";
13+
import TableMode from "./types/TableMode.js";
1314

1415
// Texts
15-
import { LOAD_MORE_TEXT } from "./generated/i18n/i18n-defaults.js";
16+
import {
17+
LOAD_MORE_TEXT,
18+
ARIA_LABEL_SELECT_ALL_CHECKBOX,
19+
TABLE_HEADER_ROW_TEXT,
20+
} from "./generated/i18n/i18n-defaults.js";
1621

1722
// Template
1823
import TableTemplate from "./generated/templates/TableTemplate.lit.js";
@@ -191,6 +196,25 @@ const metadata = {
191196
type: Boolean,
192197
},
193198

199+
/**
200+
* Defines the mode of the <code>ui5-table</code>.
201+
* <br><br>
202+
* Available options are:
203+
* <ul>
204+
* <li><code>MultiSelect</code></li>
205+
* <li><code>SingleSelect</code></li>
206+
* <li><code>None</code></li>
207+
* <ul>
208+
* @type {TableMode}
209+
* @defaultvalue "None"
210+
* @since 1.0.0-rc.15
211+
* @public
212+
*/
213+
mode: {
214+
type: TableMode,
215+
defaultValue: TableMode.None,
216+
},
217+
194218
_hiddenColumns: {
195219
type: Object,
196220
multiple: true,
@@ -223,13 +247,24 @@ const metadata = {
223247
_inViewport: {
224248
type: Boolean,
225249
},
250+
251+
/**
252+
* Defines whether all rows are selected or not when table is in MultiSelect mode.
253+
* @type {Boolean}
254+
* @defaultvalue false
255+
* @since 1.0.0-rc.15
256+
* @private
257+
*/
258+
_allRowsSelected: {
259+
type: Boolean,
260+
},
226261
},
227262
events: /** @lends sap.ui.webcomponents.main.Table.prototype */ {
228263
/**
229-
* Fired when a row is clicked.
264+
* Fired when a row in <code>Active</code> mode is clicked or <code>Enter</code> key is pressed.
230265
*
231266
* @event sap.ui.webcomponents.main.Table#row-click
232-
* @param {HTMLElement} row the clicked row.
267+
* @param {HTMLElement} row the activated row.
233268
* @public
234269
*/
235270
"row-click": {
@@ -262,6 +297,23 @@ const metadata = {
262297
* @since 1.0.0-rc.11
263298
*/
264299
"load-more": {},
300+
301+
/**
302+
* Fired when selection is changed by user interaction
303+
* in <code>SingleSelect</code> and <code>MultiSelect</code> modes.
304+
*
305+
* @event sap.ui.webcomponents.main.Table#selection-change
306+
* @param {Array} selectedRows An array of the selected rows.
307+
* @param {Array} previouslySelectedRows An array of the previously selected rows.
308+
* @public
309+
* @since 1.0.0-rc.15
310+
*/
311+
"selection-change": {
312+
detail: {
313+
selectedRows: { type: Array },
314+
previouslySelectedRows: { type: Array },
315+
},
316+
},
265317
},
266318
};
267319

@@ -345,6 +397,7 @@ class Table extends UI5Element {
345397
this.i18nBundle = getI18nBundle("@ui5/webcomponents");
346398

347399
this.tableEndObserved = false;
400+
this.addEventListener("ui5-selection-requested", this._handleSelect.bind(this));
348401
}
349402

350403
onBeforeRendering() {
@@ -360,6 +413,7 @@ class Table extends UI5Element {
360413
row._busy = this.busy;
361414
row.removeEventListener("ui5-_focused", this.fnOnRowFocused);
362415
row.addEventListener("ui5-_focused", this.fnOnRowFocused);
416+
row.mode = this.mode;
363417
});
364418

365419
this.visibleColumns = this.columns.filter((column, index) => {
@@ -446,6 +500,79 @@ class Table extends UI5Element {
446500
this.fireEvent("load-more");
447501
}
448502

503+
_handleSingleSelect(event) {
504+
const row = this.getRowParent(event.target);
505+
if (!row.selected) {
506+
const previouslySelectedRows = this.selectedRows;
507+
this.rows.forEach(item => {
508+
if (item.selected) {
509+
item.selected = false;
510+
}
511+
});
512+
row.selected = true;
513+
this.fireEvent("selection-change", {
514+
selectedRows: [row],
515+
previouslySelectedRows,
516+
});
517+
}
518+
}
519+
520+
_handleMultiSelect(event) {
521+
const row = this.getRowParent(event.target);
522+
const previouslySelectedRows = this.selectedRows;
523+
524+
row.selected = !row.selected;
525+
526+
const selectedRows = this.selectedRows;
527+
528+
if (selectedRows.length === this.rows.length) {
529+
this._allRowsSelected = true;
530+
} else {
531+
this._allRowsSelected = false;
532+
}
533+
534+
this.fireEvent("selection-change", {
535+
selectedRows,
536+
previouslySelectedRows,
537+
});
538+
}
539+
540+
_handleSelect(event) {
541+
this[`_handle${this.mode}`](event);
542+
}
543+
544+
_selectAll(event) {
545+
const bAllSelected = event.target.checked;
546+
const previouslySelectedRows = this.rows.filter(row => row.selected);
547+
548+
this._allRowsSelected = bAllSelected;
549+
550+
this.rows.forEach(row => {
551+
row.selected = bAllSelected;
552+
});
553+
554+
const selectedRows = bAllSelected ? this.rows : [];
555+
556+
this.fireEvent("selection-change", {
557+
selectedRows,
558+
previouslySelectedRows,
559+
});
560+
}
561+
562+
getRowParent(child) {
563+
const parent = child.parentElement;
564+
565+
if (child.hasAttribute("ui5-table-row")) {
566+
return child;
567+
}
568+
569+
if (parent && parent.hasAttribute("ui5-table-row")) {
570+
return parent;
571+
}
572+
573+
this.getRowParent(parent);
574+
}
575+
449576
getColumnHeader() {
450577
return this.getDomRef() && this.getDomRef().querySelector(`#${this._id}-columnHeader`);
451578
}
@@ -479,7 +606,9 @@ class Table extends UI5Element {
479606
});
480607

481608
if (visibleColumnsIndexes.length) {
482-
this.columns[visibleColumnsIndexes[0]].first = true;
609+
if (!this.isMultiSelect) {
610+
this.columns[visibleColumnsIndexes[0]].first = true;
611+
}
483612
this.columns[visibleColumnsIndexes[visibleColumnsIndexes.length - 1]].last = true;
484613
}
485614

@@ -550,6 +679,19 @@ class Table extends UI5Element {
550679
return this.moreText || this.i18nBundle.getText(LOAD_MORE_TEXT);
551680
}
552681

682+
get ariaLabelText() {
683+
const headerRowText = this.i18nBundle.getText(TABLE_HEADER_ROW_TEXT);
684+
const columnsTitle = this.columns.map(column => {
685+
return column.textContent.trim();
686+
}).join(" ");
687+
688+
return `${headerRowText} ${columnsTitle}`;
689+
}
690+
691+
get ariaLabelSelectAllText() {
692+
return this.i18nBundle.getText(ARIA_LABEL_SELECT_ALL_CHECKBOX);
693+
}
694+
553695
get loadMoreAriaLabelledBy() {
554696
if (this.moreDataText) {
555697
return `${this._id}-showMore-text ${this._id}-showMore-desc`;
@@ -569,6 +711,14 @@ class Table extends UI5Element {
569711

570712
return this._inViewport ? "absolute" : "sticky";
571713
}
714+
715+
get isMultiSelect() {
716+
return this.mode === "MultiSelect";
717+
}
718+
719+
get selectedRows() {
720+
return this.rows.filter(row => row.selected);
721+
}
572722
}
573723

574724
Table.define();

‎packages/main/src/TableCell.js

-8
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,6 @@ const metadata = {
2323
},
2424
},
2525
properties: /** @lends sap.ui.webcomponents.main.TableCell.prototype */ {
26-
27-
/**
28-
* @private
29-
*/
30-
firstInRow: {
31-
type: Boolean,
32-
},
33-
3426
/**
3527
* @private
3628
*/

‎packages/main/src/TableRow.hbs

+21
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,32 @@
55
@click="{{_onrowclick}}"
66
@keydown="{{_onkeydown}}"
77
@keyup="{{_onkeyup}}"
8+
@mouseup="{{_onmouseup}}"
9+
@touchstart="{{_ontouchstart}}"
10+
@touchend="{{_ontouchend}}"
811
aria-label="{{ariaLabelText}}"
12+
aria-selected="{{this.selected}}"
913
data-sap-focus-ref
1014
part="row"
1115
role="row"
1216
>
17+
18+
{{#if isMultiSelect}}
19+
<td
20+
class="ui5-table-multi-select-cell"
21+
aria-hidden="true"
22+
role="presentation"
23+
>
24+
<ui5-checkbox
25+
class="ui5-multi-select-checkbox"
26+
?checked="{{this.selected}}"
27+
aria-label="{{ariaLabelRowSelection}}"
28+
@ui5-change="{{_handleSelection}}"
29+
>
30+
</ui5-checkbox>
31+
</td>
32+
{{/if}}
33+
1334
{{#if shouldPopin}}
1435
{{#each visibleCells}}
1536
<slot name="{{this._individualSlot}}"></slot>

0 commit comments

Comments
 (0)
Please sign in to comment.