From f0b262ad17338f577cc4b53f092b029af876b5d9 Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Wed, 28 Feb 2024 21:36:38 -0600 Subject: [PATCH] Fix async selection Short debounce times can make requests trample over each other. Deselect should clear the hidden field even if no selected option is found (due to options being loaded async, not because of lack of selection). Filtering when ensuring selection shouldn't re-commit. If it does, it won't find the selected option. --- .../javascripts/controllers/hw_combobox_controller.js | 2 +- app/assets/javascripts/hw_combobox/helpers.js | 4 +--- .../javascripts/hw_combobox/models/combobox/selection.js | 7 +++---- test/system/hotwire_combobox_test.rb | 5 +++-- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/controllers/hw_combobox_controller.js b/app/assets/javascripts/controllers/hw_combobox_controller.js index 8994c4e..d1b3101 100644 --- a/app/assets/javascripts/controllers/hw_combobox_controller.js +++ b/app/assets/javascripts/controllers/hw_combobox_controller.js @@ -73,7 +73,7 @@ export default class HwComboboxController extends Concerns(...concerns) { endOfOptionsStreamTargetConnected(element) { const inputType = element.dataset.inputType - if (inputType) { + if (inputType && inputType !== "hw:ensureSelection") { this._commitFilter({ inputType }) } else { this._preselectOption() diff --git a/app/assets/javascripts/hw_combobox/helpers.js b/app/assets/javascripts/hw_combobox/helpers.js index 4994a99..24aec33 100644 --- a/app/assets/javascripts/hw_combobox/helpers.js +++ b/app/assets/javascripts/hw_combobox/helpers.js @@ -1,5 +1,3 @@ -export const nullEvent = new Event("NULL") - export function Concerns(Base, ...mixins) { return mixins.reduce((accumulator, current) => current(accumulator), Base) } @@ -39,7 +37,7 @@ export function startsWith(string, substring) { return string.toLowerCase().startsWith(substring.toLowerCase()) } -export function debounce(fn, delay = 150) { +export function debounce(fn, delay = 300) { let timeoutId = null return (...args) => { diff --git a/app/assets/javascripts/hw_combobox/models/combobox/selection.js b/app/assets/javascripts/hw_combobox/models/combobox/selection.js index 61a9610..e5cd83d 100644 --- a/app/assets/javascripts/hw_combobox/models/combobox/selection.js +++ b/app/assets/javascripts/hw_combobox/models/combobox/selection.js @@ -1,5 +1,5 @@ import Combobox from "hw_combobox/models/combobox/base" -import { wrapAroundAccess, nullEvent } from "hw_combobox/helpers" +import { wrapAroundAccess } from "hw_combobox/helpers" Combobox.Selection = Base => class extends Base { selectOption(event) { @@ -32,8 +32,6 @@ Combobox.Selection = Base => class extends Base { if (selected) { this.hiddenFieldTarget.value = option.dataset.value option.scrollIntoView({ block: "nearest" }) - } else { - this.hiddenFieldTarget.value = null } } @@ -48,6 +46,7 @@ Combobox.Selection = Base => class extends Base { _deselect() { const option = this._selectedOptionElement if (option) this._commitSelection(option, { selected: false }) + this.hiddenFieldTarget.value = null } _selectNew() { @@ -74,7 +73,7 @@ Combobox.Selection = Base => class extends Base { _ensureSelection() { if (this._shouldEnsureSelection) { this._select(this._ensurableOption, { force: true }) - this.filter(nullEvent) + this.filter({ inputType: "hw:ensureSelection" }) } } diff --git a/test/system/hotwire_combobox_test.rb b/test/system/hotwire_combobox_test.rb index c33682a..5ff25f5 100644 --- a/test/system/hotwire_combobox_test.rb +++ b/test/system/hotwire_combobox_test.rb @@ -93,9 +93,9 @@ class HotwireComboboxTest < ApplicationSystemTestCase open_combobox "#movie-field" type_in_combobox "#movie-field", "12" type_in_combobox "#movie-field", " " - sleep 0.5 # wait for async filter + sleep 0.7 # wait for async filter type_in_combobox "#movie-field", "ang", :enter - sleep 0.5 # wait for async filter + sleep 0.7 # wait for async filter assert_combobox_display_and_value "#movie-field", "12 Angry Men", movies("12_angry_men").id end @@ -458,6 +458,7 @@ class HotwireComboboxTest < ApplicationSystemTestCase assert_options_with count: 2 type_in_combobox "#movie-field", :backspace # clear autocompleted portion delete_from_combobox "#movie-field", "wh", original: "wh" + assert_combobox_display_and_value "#movie-field", "", nil assert_text "12 Angry Men" # pagination