Skip to content

Commit e76e1ac

Browse files
committed
chore: samples and small fixes
1 parent b79dc39 commit e76e1ac

File tree

10 files changed

+285
-6
lines changed

10 files changed

+285
-6
lines changed

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

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3179,3 +3179,124 @@ describe("Validation inside a form", () => {
31793179
.should("have.been.calledOnce");
31803180
});
31813181
});
3182+
3183+
describe("SelectedValue API", () => {
3184+
it("should clear selectedValue when clear icon is clicked", () => {
3185+
cy.mount(
3186+
<ComboBox value="Germany" selectedValue="DE" showClearIcon>
3187+
<ComboBoxItem text="Austria" value="AT"></ComboBoxItem>
3188+
<ComboBoxItem text="Germany" value="DE"></ComboBoxItem>
3189+
<ComboBoxItem text="France" value="FR"></ComboBoxItem>
3190+
</ComboBox>
3191+
);
3192+
3193+
cy.get("[ui5-combobox]")
3194+
.as("combo")
3195+
.should("have.attr", "selected-value", "DE")
3196+
.should("have.attr", "value", "Germany");
3197+
3198+
// Click the clear icon
3199+
cy.get("@combo")
3200+
.shadow()
3201+
.find(".ui5-input-clear-icon-wrapper")
3202+
.realClick();
3203+
3204+
cy.get("@combo")
3205+
.should("have.attr", "value", "")
3206+
.should("not.have.attr", "selected-value");
3207+
});
3208+
3209+
it("should correctly select items with same text but different values", () => {
3210+
cy.mount(
3211+
<ComboBox>
3212+
<ComboBoxItem text="John Smith" additionalText="Sales" value="emp-101"></ComboBoxItem>
3213+
<ComboBoxItem text="John Smith" additionalText="Engineering" value="emp-205"></ComboBoxItem>
3214+
<ComboBoxItem text="John Smith" additionalText="Marketing" value="emp-342"></ComboBoxItem>
3215+
</ComboBox>
3216+
);
3217+
3218+
cy.get("[ui5-combobox]")
3219+
.as("combo")
3220+
.invoke('on', 'ui5-selection-change', cy.spy().as('selectionChangeSpy'));
3221+
3222+
// Open dropdown and click first John Smith (Sales)
3223+
cy.get("@combo")
3224+
.shadow()
3225+
.find("[ui5-icon]")
3226+
.realClick();
3227+
3228+
cy.get("[ui5-cb-item]").eq(0).realClick();
3229+
3230+
cy.get("@combo")
3231+
.should("have.attr", "value", "John Smith")
3232+
.should("have.attr", "selected-value", "emp-101");
3233+
3234+
// Open dropdown and click second John Smith (Engineering)
3235+
cy.get("@combo")
3236+
.shadow()
3237+
.find("[ui5-icon]")
3238+
.realClick();
3239+
3240+
cy.get("[ui5-cb-item]").eq(1).realClick();
3241+
3242+
cy.get("@combo")
3243+
.should("have.attr", "value", "John Smith")
3244+
.should("have.attr", "selected-value", "emp-205");
3245+
3246+
cy.get("@selectionChangeSpy").should("have.been.calledTwice");
3247+
});
3248+
3249+
it("should return item value in formFormattedValue for form submission", () => {
3250+
cy.mount(
3251+
<form id="test-form">
3252+
<ComboBox name="country" value="Germany" selectedValue="DE">
3253+
<ComboBoxItem text="Austria" value="AT"></ComboBoxItem>
3254+
<ComboBoxItem text="Germany" value="DE"></ComboBoxItem>
3255+
<ComboBoxItem text="France" value="FR"></ComboBoxItem>
3256+
</ComboBox>
3257+
</form>
3258+
);
3259+
3260+
cy.get("[ui5-combobox]")
3261+
.as("combo")
3262+
.then(($combo) => {
3263+
const comboBox = $combo[0] as ComboBox;
3264+
// formFormattedValue should return the item's value, not the display text
3265+
expect(comboBox.formFormattedValue).to.equal("DE");
3266+
});
3267+
3268+
// Change selection to France
3269+
cy.get("@combo")
3270+
.shadow()
3271+
.find("[ui5-icon]")
3272+
.realClick();
3273+
3274+
cy.get("[ui5-cb-item]").eq(2).realClick();
3275+
3276+
cy.get("@combo")
3277+
.then(($combo) => {
3278+
const comboBox = $combo[0] as ComboBox;
3279+
expect(comboBox.formFormattedValue).to.equal("FR");
3280+
});
3281+
});
3282+
3283+
it("should fallback to display text in formFormattedValue when item has no value", () => {
3284+
cy.mount(
3285+
<form id="test-form">
3286+
<ComboBox name="country" value="Germany">
3287+
<ComboBoxItem text="Austria"></ComboBoxItem>
3288+
<ComboBoxItem text="Germany"></ComboBoxItem>
3289+
<ComboBoxItem text="France"></ComboBoxItem>
3290+
</ComboBox>
3291+
</form>
3292+
);
3293+
3294+
cy.get("[ui5-combobox]")
3295+
.as("combo")
3296+
.then(($combo) => {
3297+
const comboBox = $combo[0] as ComboBox;
3298+
// Without item values, formFormattedValue should return the display text
3299+
expect(comboBox.formFormattedValue).to.equal("Germany");
3300+
});
3301+
});
3302+
});

packages/main/src/ComboBox.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,11 +237,21 @@ class ComboBox extends UI5Element implements IFormInputElement {
237237
value = "";
238238

239239
/**
240-
* Defines the selected item value.
241-
* @default undefined
240+
* Defines the selected item's value.
241+
*
242+
* Use this property together with the `value` property on `ui5-cb-item` to:
243+
* - Select an item programmatically by its unique identifier
244+
* - Handle items with identical display text but different underlying values
245+
* - Submit machine-readable values in forms (the `value` property is submitted instead of the display text)
246+
*
247+
* When set, the ComboBox finds and selects the item whose `value` matches this property
248+
* and whose `text` matches the ComboBox's `value` (display text).
249+
*
250+
* **Note:** This replaces the deprecated `selected` property on `ui5-cb-item`.
251+
* @default undefined
242252
* @public
243253
* @since 2.19.0
244-
*/
254+
*/
245255
@property()
246256
selectedValue?: string;
247257

@@ -487,6 +497,15 @@ class ComboBox extends UI5Element implements IFormInputElement {
487497
}
488498

489499
get formFormattedValue() {
500+
// Find the selected item
501+
const selectedItem = this._getItems().find(item => item.selected && !item.isGroupItem) as ComboBoxItem | undefined;
502+
503+
// If selected item has a value property, return it (like Select does)
504+
if (selectedItem && selectedItem.value !== undefined) {
505+
return selectedItem.value;
506+
}
507+
508+
// Fallback to display text (backward compatibility)
490509
return this.value;
491510
}
492511

@@ -1357,6 +1376,9 @@ class ComboBox extends UI5Element implements IFormInputElement {
13571376
}
13581377

13591378
this.value = "";
1379+
if (this._useSelectedValue) {
1380+
this.selectedValue = undefined;
1381+
}
13601382
this.fireDecoratorEvent("input");
13611383

13621384
if (this._isPhone) {

packages/main/src/ComboBoxItem.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,22 @@ class ComboBoxItem extends ListItemBase implements IComboBoxItem {
4646
_isVisible = false;
4747

4848
/**
49-
* Defines the value of the `ui5-combobox-item`.
50-
* Used for selection. Check ComboBox' selectedValue property for more information.
49+
* Defines the value of the `ui5-cb-item`.
50+
*
51+
* Use this property to associate a unique identifier or machine-readable value with the item,
52+
* separate from the display text. This enables:
53+
* - Selecting items programmatically via `selectedValue` on the ComboBox
54+
* - Submitting machine-readable values in forms
55+
* - Distinguishing between items with identical display text
56+
*
57+
* **Example:**
58+
* ```html
59+
* <ui5-combobox selected-value="DE">
60+
* <ui5-cb-item text="Germany" value="DE"></ui5-cb-item>
61+
* <ui5-cb-item text="France" value="FR"></ui5-cb-item>
62+
* </ui5-combobox>
63+
* ```
64+
*
5165
* @default undefined
5266
* @public
5367
* @since 2.19.0
@@ -65,6 +79,7 @@ class ComboBoxItem extends ListItemBase implements IComboBoxItem {
6579
/**
6680
* Indicates whether the item is selected
6781
* @protected
82+
* @deprecated use value property of the item and selectedValue property of the ComboBox instead
6883
*/
6984
@property({ type: Boolean })
7085
selected = false;

packages/website/docs/_components_pages/main/ComboBox/ComboBox.mdx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import Filters from "../../../_samples/main/ComboBox/Filters/Filters.md";
88
import TwoColumnsLayout from "../../../_samples/main/ComboBox/TwoColumnsLayout/TwoColumnsLayout.md";
99
import Grouping from "../../../_samples/main/ComboBox/Grouping/Grouping.md";
1010
import SuggestionsWrapping from "../../../_samples/main/ComboBox/SuggestionsWrapping/SuggestionsWrapping.md";
11+
import SelectedValue from "../../../_samples/main/ComboBox/SelectedValue/SelectedValue.md";
12+
import SameTextDifferentValues from "../../../_samples/main/ComboBox/SameTextDifferentValues/SameTextDifferentValues.md";
1113

1214
<%COMPONENT_OVERVIEW%>
1315

@@ -42,4 +44,16 @@ Grouping of items can be implented via the ui5-cb-group-item web component.
4244
### Items Text Wrapping
4345
The sample demonstrates how the text of the items wrap when too long.
4446

45-
<SuggestionsWrapping />
47+
<SuggestionsWrapping />
48+
49+
### Selected Value
50+
Use the `value` property on items and `selected-value` on the ComboBox to decouple the display text from the underlying selection value.
51+
This is useful for form submission, programmatic selection, and handling items with identical display text.
52+
53+
<SelectedValue />
54+
55+
### Items with Same Text but Different Values
56+
When you have multiple items with identical display text (e.g., employees with the same name), use the `value` property to uniquely identify each item.
57+
The `additional-text` property helps users distinguish between items visually.
58+
59+
<SameTextDifferentValues />
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import html from '!!raw-loader!./sample.html';
2+
import js from '!!raw-loader!./main.js';
3+
4+
<Editor html={html} js={js} />
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import "@ui5/webcomponents/dist/ComboBox.js";
2+
import "@ui5/webcomponents/dist/ComboBoxItem.js";
3+
4+
const combo = document.getElementById("employee-combo");
5+
const employeeId = document.getElementById("employee-id");
6+
const employeeName = document.getElementById("employee-name");
7+
const employeeDept = document.getElementById("employee-dept");
8+
9+
combo.addEventListener("selection-change", (event) => {
10+
const item = event.detail.item;
11+
if (item) {
12+
employeeId.textContent = item.value;
13+
employeeName.textContent = item.text;
14+
employeeDept.textContent = item.additionalText;
15+
} else {
16+
employeeId.textContent = "-";
17+
employeeName.textContent = "-";
18+
employeeDept.textContent = "-";
19+
}
20+
});
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<!-- playground-fold -->
2+
<!DOCTYPE html>
3+
<html lang="en">
4+
5+
<head>
6+
<meta charset="UTF-8">
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
8+
<title>Sample</title>
9+
</head>
10+
11+
<body style="background-color: var(--sapBackgroundColor); height: 350px">
12+
<!-- playground-fold-end -->
13+
14+
<ui5-combobox id="employee-combo" placeholder="Select an employee">
15+
<ui5-cb-item text="John Smith" additional-text="Sales" value="emp-101"></ui5-cb-item>
16+
<ui5-cb-item text="John Smith" additional-text="Engineering" value="emp-205"></ui5-cb-item>
17+
<ui5-cb-item text="John Smith" additional-text="Marketing" value="emp-342"></ui5-cb-item>
18+
<ui5-cb-item text="Jane Doe" additional-text="HR" value="emp-118"></ui5-cb-item>
19+
<ui5-cb-item text="Jane Doe" additional-text="Finance" value="emp-267"></ui5-cb-item>
20+
</ui5-combobox>
21+
22+
<div id="output" style="margin-top: 1rem; font-family: var(--sapFontFamily); color: var(--sapTextColor);">
23+
<div>Employee ID: <strong id="employee-id">-</strong></div>
24+
<div>Name: <strong id="employee-name">-</strong></div>
25+
<div>Department: <strong id="employee-dept">-</strong></div>
26+
</div>
27+
28+
<!-- playground-fold -->
29+
<script type="module" src="main.js"></script>
30+
</body>
31+
32+
</html>
33+
<!-- playground-fold-end -->
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import html from '!!raw-loader!./sample.html';
2+
import js from '!!raw-loader!./main.js';
3+
4+
<Editor html={html} js={js} />
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import "@ui5/webcomponents/dist/ComboBox.js";
2+
import "@ui5/webcomponents/dist/ComboBoxItem.js";
3+
4+
const combo = document.getElementById("country-combo");
5+
const output = document.getElementById("selected-value");
6+
7+
combo.addEventListener("selection-change", (event) => {
8+
const item = event.detail.item;
9+
if (item) {
10+
output.textContent = item.value || "(no value)";
11+
} else {
12+
output.textContent = "(none)";
13+
}
14+
});
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<!-- playground-fold -->
2+
<!DOCTYPE html>
3+
<html lang="en">
4+
5+
<head>
6+
<meta charset="UTF-8">
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
8+
<title>Sample</title>
9+
</head>
10+
11+
<body style="background-color: var(--sapBackgroundColor); height: 350px">
12+
<!-- playground-fold-end -->
13+
14+
<ui5-combobox id="country-combo" placeholder="Select a country" selected-value="DE">
15+
<ui5-cb-item text="Austria" value="AT"></ui5-cb-item>
16+
<ui5-cb-item text="Belgium" value="BE"></ui5-cb-item>
17+
<ui5-cb-item text="France" value="FR"></ui5-cb-item>
18+
<ui5-cb-item text="Germany" value="DE"></ui5-cb-item>
19+
<ui5-cb-item text="Italy" value="IT"></ui5-cb-item>
20+
<ui5-cb-item text="Spain" value="ES"></ui5-cb-item>
21+
</ui5-combobox>
22+
23+
<div id="output" style="margin-top: 1rem; font-family: var(--sapFontFamily); color: var(--sapTextColor);">
24+
Selected value: <strong id="selected-value">DE</strong>
25+
</div>
26+
27+
<!-- playground-fold -->
28+
<script type="module" src="main.js"></script>
29+
</body>
30+
31+
</html>
32+
<!-- playground-fold-end -->

0 commit comments

Comments
 (0)