Skip to content

Commit d85561a

Browse files
authoredJun 28, 2021
fix(ui5-combobox): enable setting value programatically (#3253)
BREAKING CHANGE: filter value property is removed. FIXES: #2233
1 parent 658328a commit d85561a

File tree

5 files changed

+157
-75
lines changed

5 files changed

+157
-75
lines changed
 

‎packages/main/src/ComboBox.hbs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
{{/if}}
55

66
<input id="ui5-combobox-input"
7-
.value="{{_tempValue}}"
7+
.value="{{value}}"
88
inner-input
99
placeholder="{{placeholder}}"
1010
?disabled={{disabled}}

‎packages/main/src/ComboBox.js

+74-70
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,14 @@ const metadata = {
7070
/**
7171
* Defines the "live" value of the component.
7272
* <br><br>
73-
* <b>Note:</b> The property is updated upon typing.
73+
* <b>Note:</b> If we have an item e.g. "Bulgaria", "B" is typed, "ulgaria" is typed ahead, value will be "Bulgaria", filterValue will be "B".
7474
*
7575
* <br><br>
7676
* <b>Note:</b> Initially the filter value is synced with value.
7777
*
7878
* @type {string}
7979
* @defaultvalue ""
80-
* @public
80+
* @private
8181
*/
8282
filterValue: {
8383
type: String,
@@ -216,11 +216,6 @@ const metadata = {
216216
noAttribute: true,
217217
},
218218

219-
_tempValue: {
220-
type: String,
221-
defaultValue: "",
222-
},
223-
224219
_filteredItems: {
225220
type: Object,
226221
},
@@ -384,27 +379,8 @@ class ComboBox extends UI5Element {
384379
}
385380

386381
onBeforeRendering() {
387-
let domValue;
388-
389382
if (this._initialRendering) {
390-
domValue = this.value;
391383
this._filteredItems = this.items;
392-
} else {
393-
domValue = this.filterValue;
394-
}
395-
396-
if (this._autocomplete && domValue !== "") {
397-
const item = this._autoCompleteValue(domValue);
398-
399-
if (!this._selectionChanged && (item && !item.selected)) {
400-
this.fireEvent("selection-change", {
401-
item,
402-
});
403-
404-
this._selectionChanged = false;
405-
}
406-
} else {
407-
this._tempValue = domValue;
408384
}
409385

410386
if (!this._initialRendering && this.popover && document.activeElement === this && !this._filteredItems.length) {
@@ -413,12 +389,6 @@ class ComboBox extends UI5Element {
413389

414390
this._selectMatchingItem();
415391

416-
if (this._isKeyNavigation && this.responsivePopover && this.responsivePopover.opened) {
417-
this.focused = false;
418-
} else if (this.shadowRoot.activeElement) {
419-
this.focused = this.shadowRoot.activeElement.id === "ui5-combobox-input";
420-
}
421-
422392
this._initialRendering = false;
423393
this._isKeyNavigation = false;
424394
}
@@ -447,28 +417,21 @@ class ComboBox extends UI5Element {
447417
_focusin(event) {
448418
this.focused = true;
449419

450-
if (this.filterValue !== this.value) {
451-
this.filterValue = this.value;
452-
}
420+
this._lastValue = this.value;
453421

454422
!isPhone() && event.target.setSelectionRange(0, this.value.length);
455423
}
456424

457425
_focusout() {
458426
this.focused = false;
459427

460-
this._inputChange();
428+
this._fireChangeEvent();
429+
461430
!isPhone() && this._closeRespPopover();
462431
}
463432

464433
_afterOpenPopover() {
465434
this._iconPressed = true;
466-
467-
if (isPhone() && this.value) {
468-
this.filterValue = this.value;
469-
}
470-
471-
this._clearFocus();
472435
}
473436

474437
_afterClosePopover() {
@@ -480,6 +443,11 @@ class ComboBox extends UI5Element {
480443
if (isPhone()) {
481444
this.blur();
482445
}
446+
447+
if (this._selectionPerformed) {
448+
this._lastValue = this.value;
449+
this._selectionPerformed = false;
450+
}
483451
}
484452

485453
_toggleRespPopover() {
@@ -539,12 +507,28 @@ class ComboBox extends UI5Element {
539507
event.stopImmediatePropagation();
540508
}
541509

542-
this._clearFocus();
543-
this._tempFilterValue = value;
510+
this._filteredItems = this._filterItems(value);
511+
this.value = value;
544512
this.filterValue = value;
545-
this.fireEvent("input");
546513

547-
this._filteredItems = this._filterItems(value);
514+
this._clearFocus();
515+
516+
// autocomplete
517+
if (this._autocomplete && value !== "") {
518+
const item = this._autoCompleteValue(value);
519+
520+
if (!this._selectionChanged && (item && !item.selected)) {
521+
this.fireEvent("selection-change", {
522+
item,
523+
});
524+
525+
this._selectionChanged = false;
526+
527+
item.focused = true;
528+
}
529+
}
530+
531+
this.fireEvent("input");
548532

549533
if (isPhone()) {
550534
return;
@@ -597,14 +581,23 @@ class ComboBox extends UI5Element {
597581
}
598582

599583
this._filteredItems[indexOfItem].focused = true;
600-
this.filterValue = this._filteredItems[indexOfItem].text;
584+
this._filteredItems[indexOfItem].selected = true;
585+
586+
this.value = this._filteredItems[indexOfItem].text;
587+
588+
// autocomplete
589+
const item = this._autoCompleteValue(this.value);
590+
591+
if ((item && !item.selected)) {
592+
this.fireEvent("selection-change", {
593+
item,
594+
});
595+
}
596+
601597
this._isKeyNavigation = true;
602598
this._itemFocused = true;
603599
this.fireEvent("input");
604-
605-
this.fireEvent("selection-change", {
606-
item: this._filteredItems[indexOfItem],
607-
});
600+
this._fireChangeEvent();
608601

609602
this._selectionChanged = true;
610603
}
@@ -618,7 +611,7 @@ class ComboBox extends UI5Element {
618611
}
619612

620613
if (isEnter(event)) {
621-
this._inputChange();
614+
this._fireChangeEvent();
622615
this._closeRespPopover();
623616
}
624617

@@ -639,7 +632,6 @@ class ComboBox extends UI5Element {
639632
if (isPhone() && event && event.target.classList.contains("ui5-responsive-popover-close-btn") && this._selectedItemText) {
640633
this.value = this._selectedItemText;
641634
this.filterValue = this._selectedItemText;
642-
this._tempValue = this._selectedItemText;
643635
}
644636

645637
this.responsivePopover.close();
@@ -654,23 +646,21 @@ class ComboBox extends UI5Element {
654646
}
655647

656648
_autoCompleteValue(current) {
657-
const currentValue = current;
658-
const matchingItems = this._startsWithMatchingItems(currentValue);
659-
const selectionValue = this._tempFilterValue ? this._tempFilterValue : currentValue;
649+
const matchingItems = this._startsWithMatchingItems(current);
660650

661651
if (matchingItems.length) {
662-
this._tempValue = matchingItems[0] ? matchingItems[0].text : current;
652+
this.value = matchingItems[0] ? matchingItems[0].text : current;
663653
} else {
664-
this._tempValue = current;
654+
this.value = current;
665655
}
666656

667-
if (matchingItems.length && (selectionValue !== this._tempValue && this.value !== this._tempValue)) {
657+
if (this._isKeyNavigation) {
668658
setTimeout(() => {
669-
this.inner.setSelectionRange(selectionValue.length, this._tempValue.length);
659+
this.inner.setSelectionRange(0, this.value.length);
670660
}, 0);
671-
} else if (this._isKeyNavigation) {
661+
} else if (matchingItems.length) {
672662
setTimeout(() => {
673-
this.inner.setSelectionRange(0, this._tempValue.length);
663+
this.inner.setSelectionRange(this.filterValue.length, this.value.length);
674664
}, 0);
675665
}
676666

@@ -681,30 +671,41 @@ class ComboBox extends UI5Element {
681671

682672
_selectMatchingItem() {
683673
this._filteredItems = this._filteredItems.map(item => {
684-
item.selected = (item.text === this._tempValue);
674+
item.selected = (item.text === this.value);
685675

686676
return item;
687677
});
688678
}
689679

690-
_inputChange() {
691-
if (this.value !== this._tempValue) {
692-
this.value = this._tempValue;
680+
_fireChangeEvent() {
681+
if (this.value !== this._lastValue) {
693682
this.fireEvent("change");
694-
this.inner.setSelectionRange(this.value.length, this.value.length);
683+
this._lastValue = this.value;
695684
}
696685
}
697686

687+
_inputChange(event) {
688+
event.preventDefault();
689+
}
690+
698691
_itemMousedown(event) {
699692
event.preventDefault();
700693
}
701694

702695
_selectItem(event) {
703696
const listItem = event.detail.item;
704697

705-
this._tempValue = listItem.mappedItem.text;
706698
this._selectedItemText = listItem.mappedItem.text;
707-
this.filterValue = this._tempValue;
699+
this._selectionPerformed = true;
700+
701+
const sameItemSelected = this.value === this._selectedItemText;
702+
const sameSelectionPerformed = this.value.toLowerCase() === this.filterValue.toLowerCase();
703+
704+
if (sameItemSelected && sameSelectionPerformed) {
705+
return this._closeRespPopover();
706+
}
707+
708+
this.value = this._selectedItemText;
708709

709710
if (!listItem.mappedItem.selected) {
710711
this.fireEvent("selection-change", {
@@ -720,8 +721,11 @@ class ComboBox extends UI5Element {
720721
return item;
721722
});
722723

723-
this._inputChange();
724+
this._fireChangeEvent();
724725
this._closeRespPopover();
726+
727+
// reset selection
728+
this.inner.setSelectionRange(this.value.length, this.value.length);
725729
}
726730

727731
_onItemFocus(event) {

‎packages/main/src/ComboBoxPopover.hbs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
>
3434
<input
3535
class="ui5-input-inner-phone"
36-
.value="{{_tempValue}}"
36+
.value="{{value}}"
3737
inner-input
3838
placeholder="{{placeholder}}"
3939
value-state="{{valueState}}"

‎packages/main/test/pages/ComboBox.html

+10-2
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@
5555
<ui5-cb-item text="Chile"></ui5-cb-item>
5656
</ui5-combobox>
5757

58+
<br>
59+
60+
<ui5-button id="value-set-btn" >Set value</ui5-button>
61+
5862
<ui5-combobox id="combo2" style="width: 360px;" aria-label="Select destination:">
5963
<ui5-cb-item text="Algeria"></ui5-cb-item>
6064
<ui5-cb-item text="Argentina"></ui5-cb-item>
@@ -197,7 +201,7 @@ <h3>ComboBox in Compact</h3>
197201

198202
<script type="module">
199203
document.getElementById("lazy").addEventListener("ui5-input", async event => {
200-
const { filterValue } = event.target;
204+
const { value } = event.target;
201205

202206
// set busy state
203207
event.target.loading = true;
@@ -238,9 +242,13 @@ <h3>ComboBox in Compact</h3>
238242
});
239243

240244
document.getElementById("input-cb").addEventListener("ui5-input", function(event) {
241-
document.getElementById("input-placeholder").innerHTML = event.target.filterValue;
245+
document.getElementById("input-placeholder").innerHTML = event.target.value;
242246
document.getElementById("input-count").innerHTML = parseInt(document.getElementById("input-count").innerHTML) + 1;
243247
});
248+
249+
document.getElementById("value-set-btn").addEventListener("click", function (event) {
250+
document.getElementById("combo").value = "new value";
251+
});
244252
</script>
245253

246254
</body>

‎packages/main/test/specs/ComboBox.spec.js

+71-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ describe("General interaction", () => {
6565
});
6666

6767
assert.strictEqual(selection, "ahrain", "ahrain should be selected");
68-
assert.strictEqual(combo.getProperty("value"), "Bulgaria", "Value should be Bulgaria");
6968
const listItems = popover.$("ui5-list").$$("ui5-li");
7069
assert.ok(listItems[0].getProperty("selected"), "List Item should be selected");
7170

@@ -190,6 +189,62 @@ describe("General interaction", () => {
190189

191190
assert.strictEqual(placeholder.getText(), "Argentina", "Text should be empty");
192191
assert.strictEqual(counter.getText(), "1", "Call count should be 1");
192+
193+
arrow.click();
194+
195+
assert.strictEqual(counter.getText(), "1", "Call count should be 1");
196+
197+
arrow.click();
198+
199+
popover.$("ui5-list").$$("ui5-li")[1].click();
200+
assert.strictEqual(counter.getText(), "2", "Call count should be 2");
201+
});
202+
203+
it ("Tests change event after pressing enter key", () => {
204+
browser.url(`http://localhost:${PORT}/test-resources/pages/ComboBox.html`);
205+
206+
const counter = $("#change-count");
207+
const combo = $("#change-cb");
208+
const input = combo.shadow$("[inner-input]");
209+
210+
input.click();
211+
212+
input.keys("Enter");
213+
input.keys("Enter");
214+
input.keys("Enter");
215+
input.keys("Enter");
216+
217+
assert.strictEqual(counter.getText(), "0", "Call count should be 0");
218+
219+
input.keys("a");
220+
221+
input.keys("Enter");
222+
input.keys("Enter");
223+
input.keys("Enter");
224+
input.keys("Enter");
225+
226+
assert.strictEqual(counter.getText(), "1", "Call count should be 1");
227+
228+
});
229+
230+
it ("Tests change event after type and item select", () => {
231+
browser.url(`http://localhost:${PORT}/test-resources/pages/ComboBox.html`);
232+
233+
const counter = $("#change-count");
234+
const combo = $("#change-cb");
235+
const input = combo.shadow$("[inner-input]");
236+
const placeholder = $("#change-placeholder");
237+
238+
input.click();
239+
input.keys("a");
240+
241+
// click on first item
242+
const staticAreaItemClassName = browser.getStaticAreaItemClassName("#change-cb");
243+
const popover = browser.$(`.${staticAreaItemClassName}`).shadow$("ui5-responsive-popover");
244+
popover.$("ui5-list").$$("ui5-li")[0].click();
245+
246+
assert.strictEqual(placeholder.getText(), "Argentina", "Text should be empty");
247+
assert.strictEqual(counter.getText(), "1", "Call count should be 1");
193248
});
194249

195250
it ("Tests input event", () => {
@@ -351,4 +406,19 @@ describe("Accessibility", () => {
351406

352407
assert.strictEqual(invisibleMessageSpan.getHTML(false), itemAnnouncement2, "Span value is correct.")
353408
});
409+
410+
it ("Tests setting value programatically", () => {
411+
browser.url(`http://localhost:${PORT}/test-resources/pages/ComboBox.html`);
412+
413+
const combo = $("#combo");
414+
const btn = $("#value-set-btn");
415+
const inner = combo.shadow$("input");
416+
417+
assert.strictEqual(combo.getProperty("value"), "Bulgaria", "Initial Value should be Bulgaria");
418+
419+
btn.click();
420+
421+
assert.strictEqual(combo.getProperty("value"), "new value", "ComboBox value should be set to 'new value'");
422+
assert.strictEqual(inner.getProperty("value"), "new value", "ComboBox value should be set to 'new value'");
423+
});
354424
});

0 commit comments

Comments
 (0)
Please sign in to comment.