Skip to content

Commit 8e9c347

Browse files
committed
feat(ui5-table): behavior property added for selections
- RowSelector: In this default mode, rows can only be selected using the row selector column. - RowOnly: Rows can only be selected by clicking directly on the row, as the row selector column is hidden. Fixes: #10893
1 parent 642101e commit 8e9c347

File tree

11 files changed

+129
-19
lines changed

11 files changed

+129
-19
lines changed

packages/main/cypress/specs/TableSelections.cy.tsx

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,9 @@ function mountTestpage(selectionMode: string) {
5959
);
6060

6161
cy.get("#table0").children("ui5-table-header-row").first().as("headerRow");
62-
cy.get("#table0").children("ui5-table-row").get("[row-key=\"0\"]").as("row0");
63-
cy.get("#table0").children("ui5-table-row").get("[row-key=\"4\"]").as("row4");
62+
[0, 1, 2, 4].forEach(key => {
63+
cy.get(`#table0`).children(`ui5-table-row[row-key="${key}"]`).as(`row${key}`);
64+
});
6465
}
6566

6667
describe("Mode - None", () => {
@@ -115,7 +116,12 @@ const testConfig = {
115116
"block_1": "0",
116117
"block_2": "3",
117118
},
118-
},
119+
"ROWONLY": {
120+
"click": "0",
121+
"space": "1",
122+
"enter": "2"
123+
}
124+
}
119125
},
120126
"Multiple": {
121127
"config": {
@@ -154,6 +160,11 @@ const testConfig = {
154160
"initial": "0",
155161
"block_1": "0 1",
156162
"block_2": "0 1 3 4"
163+
},
164+
"ROWONLY": {
165+
"click": "0",
166+
"space": "0 1",
167+
"enter": "0 1 2"
157168
}
158169
}
159170
}
@@ -292,6 +303,46 @@ Object.entries(testConfig).forEach(([mode, testConfigEntry]) => {
292303
checkSelectionChangeSpy(callCount);
293304
});
294305
});
306+
307+
describe(`Behavior - ${mode}`, () => {
308+
beforeEach(() => {
309+
mountTestpage(testConfigEntry.config.mode);
310+
311+
cy.get("@row0").invoke("prop", "interactive", true);
312+
cy.get("@row1").invoke("prop", "interactive", true);
313+
cy.get("@row2").invoke("prop", "interactive", true);
314+
cy.get("#selection").invoke("attr", "behavior", "RowWÓnly");
315+
cy.get("#table0").invoke("on", "row-click", cy.stub().as("rowClickSpy"));
316+
cy.get("#selection").invoke("on", "change", cy.stub().as("selectionChangeSpy"));
317+
});
318+
319+
it("renders neither selection cell nor selection component", () => {
320+
cy.get("@headerRow").shadow().find("#selection-cell").should("not.exist");
321+
cy.get("@row0").shadow().find("#selection-cell").should("not.exist");
322+
323+
cy.get("@headerRow").shadow().find("#selection-component").should("not.exist");
324+
cy.get("@row0").shadow().find("#selection-component").should("not.exist");
325+
});
326+
327+
it("selects row via click, space or enter", () => {
328+
cy.get("@row0").realClick();
329+
checkSelection(testConfigEntry.cases.ROWONLY.click);
330+
checkSelectionChangeSpy(1);
331+
332+
cy.get("@row0").realPress("ArrowDown");
333+
cy.get("@row1").realPress("Space");
334+
checkSelection(testConfigEntry.cases.ROWONLY.space);
335+
checkSelectionChangeSpy(2);
336+
337+
cy.get("@row1").realPress("ArrowDown");
338+
cy.get("@row2").realPress("Enter");
339+
checkSelection(testConfigEntry.cases.ROWONLY.enter);
340+
checkSelectionChangeSpy(3);
341+
342+
cy.get("@rowClickSpy").should("not.have.callCount");
343+
});
344+
});
345+
295346
});
296347

297348
describe("TableSelectionMulti", () => {

packages/main/src/Table.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,9 @@ type TableRowActionClickEventDetail = {
191191
/**
192192
* Fired when an interactive row is clicked.
193193
*
194+
* **Note:** This event is not fired if the `behavior` property of the selection component is set to `RowOnly`.
195+
* In such cases, use the `change` event of the selection component instead.
196+
*
194197
* @param {TableRow} row The row instance
195198
* @public
196199
*/

packages/main/src/TableRow.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,17 @@ class TableRow extends TableRowBase {
137137

138138
if (eventOrigin === this && this._isInteractive && isEnter(e)) {
139139
this.toggleAttribute("_active", true);
140-
this._table?._onRowClick(this);
140+
this._onclick();
141141
}
142142
}
143143

144144
_onclick() {
145-
if (this._isInteractive && this === getActiveElement()) {
146-
this._table?._onRowClick(this);
145+
if (this === getActiveElement()) {
146+
if (this._isSelectable && !this._hasRowSelector) {
147+
this._onSelectionChange();
148+
} else if (this.interactive) {
149+
this._table?._onRowClick(this);
150+
}
147151
}
148152
}
149153

@@ -162,7 +166,7 @@ class TableRow extends TableRowBase {
162166
}
163167

164168
get _isInteractive() {
165-
return this.interactive;
169+
return this.interactive || (this._isSelectable && !this._hasRowSelector);
166170
}
167171

168172
get _hasOverflowActions() {

packages/main/src/TableSelectionBase.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type Table from "./Table.js";
55
import type TableRowBase from "./TableRowBase.js";
66
import type TableRow from "./TableRow.js";
77
import type { ITableFeature } from "./Table.js";
8+
import TableSelectionBehavior from "./types/TableSelectionBehavior.js";
89

910
/**
1011
* Fired when selection is changed by user interaction.
@@ -44,6 +45,16 @@ abstract class TableSelectionBase extends UI5Element implements ITableFeature {
4445
@property()
4546
selected?: string;
4647

48+
/**
49+
* Defines the selection behavior.
50+
*
51+
* @default "RowSelector"
52+
* @public
53+
* @since 2.11
54+
*/
55+
@property()
56+
behavior: `${TableSelectionBehavior}` = "RowSelector";
57+
4758
readonly identifier = "TableSelection";
4859
protected _table?: Table;
4960

@@ -80,7 +91,7 @@ abstract class TableSelectionBase extends UI5Element implements ITableFeature {
8091
* Determines whether a row selector (for example, `radiobutton` or `checkbox`) is rendered.
8192
*/
8293
isRowSelectorRequired(): boolean {
83-
return true;
94+
return this.behavior === TableSelectionBehavior.RowSelector;
8495
}
8596

8697
/**
@@ -122,13 +133,12 @@ abstract class TableSelectionBase extends UI5Element implements ITableFeature {
122133

123134
/**
124135
* Invalidates the table and its rows to re-evaluate the selection.
125-
*
126-
* @protected
127136
*/
128137
protected _invalidateTableAndRows() {
129138
if (this._table) {
130139
this._table._invalidate++;
131140
this._table.rows.forEach(row => row._invalidate++);
141+
this._table.headerRow.forEach(row => row._invalidate++);
132142
}
133143
}
134144
}

packages/main/src/TableSelectionMulti.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,6 @@ class TableSelectionMulti extends TableSelectionBase {
137137
this.selected = [...selectedSet].join(" ");
138138
}
139139

140-
_invalidateTableAndRows() {
141-
super._invalidateTableAndRows();
142-
const headerRow = this._table?.headerRow[0];
143-
headerRow && headerRow._invalidate++;
144-
}
145-
146140
_onkeydown(e: KeyboardEvent) {
147141
if (!this._table || !e.shiftKey) {
148142
return;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* Selection behavior of the `ui5-table` selection components.
3+
*
4+
* @public
5+
* @since 2.11
6+
*/
7+
enum TableSelectionBehavior {
8+
/**
9+
* Rows can only be selected using the row selector column.
10+
* @public
11+
*/
12+
RowSelector = "RowSelector",
13+
14+
/**
15+
* Rows can only be selected by clicking directly on the row, as the row selector column is hidden.
16+
*
17+
* **Note:** In this mode, the `row-click` event of the `table` component is not fired.
18+
*
19+
* @public
20+
*/
21+
RowOnly = "RowOnly",
22+
}
23+
24+
export default TableSelectionBehavior;

packages/main/test/pages/Table.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
table.style.width = selectedItem.textContent;
8181
});
8282
table.addEventListener("row-click", (e) => {
83-
console.log(`${Date.now()}: Row with the row-key ${e.detail.row.row-key} is clicked`);
83+
console.log(`${Date.now()}: Row with the row-key ${e.detail.row.rowKey} is clicked`);
8484
});
8585

8686
const growing = document.getElementById("growing");

packages/website/docs/_samples/main/Table/SelectionMulti/main.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,9 @@ selectionFeature.addEventListener("change", (e) => {
2828
console.log("Recently deselected row-keys", recentlyDeselectedRowKeys);
2929
console.log("Recently deselected rows", recentlyDeselectedRows);
3030
}
31-
})
31+
});
32+
33+
const selectionBehavior = document.getElementById("selectionBehavior");
34+
selectionBehavior.addEventListener("change", (e) => {
35+
selectionFeature.behavior = e.target.text;
36+
});

packages/website/docs/_samples/main/Table/SelectionMulti/sample.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@
1010

1111
<body style="background-color: var(--sapBackgroundColor)">
1212
<div class="section">
13+
<div style="display: flex; align-items: center;">
14+
<ui5-label>Selection Behavior: </ui5-label>
15+
<span id="selectionBehavior" role="radiogroup">
16+
<ui5-radio-button name="selectionBehavior" text="RowSelector" checked></ui5-radio-button>
17+
<ui5-radio-button name="selectionBehavior" text="RowOnly"></ui5-radio-button>
18+
</span>
19+
</div>
1320
<!-- playground-fold-end -->
1421
<ui5-table id="table">
1522
<ui5-table-selection-multi id="selection" slot="features" selected="Row1 Row3"></ui5-table-selection-multi>

packages/website/docs/_samples/main/Table/SelectionSingle/main.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,9 @@ const selectionFeature = document.getElementById("selection");
1010
selectionFeature.addEventListener("change", (e) => {
1111
console.log("Selected key", selectionFeature.selected);
1212
console.log("Selected row", selectionFeature.getRowByKey(selectionFeature.selected));
13-
})
13+
});
14+
15+
const selectionBehavior = document.getElementById("selectionBehavior");
16+
selectionBehavior.addEventListener("change", (e) => {
17+
selectionFeature.behavior = e.target.text;
18+
});

packages/website/docs/_samples/main/Table/SelectionSingle/sample.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@
1010

1111
<body style="background-color: var(--sapBackgroundColor)">
1212
<div class="section">
13+
<div style="display: flex; align-items: center;">
14+
<ui5-label>Selection Behavior: </ui5-label>
15+
<span id="selectionBehavior" role="radiogroup">
16+
<ui5-radio-button name="selectionBehavior" text="RowSelector" checked></ui5-radio-button>
17+
<ui5-radio-button name="selectionBehavior" text="RowOnly"></ui5-radio-button>
18+
</span>
19+
</div>
1320
<!-- playground-fold-end -->
1421
<ui5-table id="table">
1522
<ui5-table-selection-single id="selection" slot="features" selected="Row2"></ui5-table-selection-single>

0 commit comments

Comments
 (0)