You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Sorry if this reads as a disjointed rant - its not intended to be. Easiest thing for me is to do a PR with the "fixes" that seem right to me, but this is not my component, neither my library, so I would like to align my expectations with what the authors intended.
While the typeahead component looks fine in the demo, using it while wired to a model that is being updated makes me feel like a pig wrestling with a pumpkin :)
Pretty standard affair - I have the component wired to a model and when the data changes - the model gets updated.
A side comment - :change-on-blur? is broken if you want to navigate with the mouse - the component only tracks the TAB key as a method of losing the focus, so for users that like to click the :on-change event never seems to be fired. So for my intents and purposes, I am going to set it to false.
The first problem that I've hit is with this piece of code which gets executed every time the component needs to be redrawn (for example, when the data source invokes the callback with a list of suggestions):
(defn- external-model-changed
"Update state when the external model value has changed."
[state new-value]
(-> state
;(assoc :external-model new-value) ;; this is missing in the implementation
(update-model new-value)
(display-suggestion new-value)
clear-suggestions))
the function never updates the value for :external-model, so in effect every time the component is redrawn, its state wrt suggestions is reset. What happens visually, is that the completion list shows up then is immediately closed. The flow of events is like this:
user presses key
input-text-on-change! gets invoked
2.1. the key press is put on a channel that is going to trigger the data source (this smells as well, but more on it in a bit)
2.2. the :model gets updated with the value
component is redrawn and the autocompletion data gets reset (its fine for now, cause the data source havent kicked in, see 2.1. above)
data source invokes the callback, the state atom changes
component gets redrawn again, autocompletion data gets reset and the list is closed :(
With the fix above, on point 5 the autocompletion data wont get reset cause the :external-model and :model will match.
Note about point 2.1. - here is the input-text-on-change! code:
(defn- input-text-on-change!
"Update state in response to `input-text` `on-change`, and put text on the `c-input` channel"
[state-atom new-text]
(let [{:as state :keys [input-text c-input]} @state-atom]
(if (= new-text input-text) state ;; keypresses that do not change the value still call on-change, ignore these
(do
(when-not (clojure.string/blank? new-text) (put! c-input new-text))
(swap! state-atom
#(cond-> %
:always (assoc :input-text new-text :displaying-suggestion? false)
(event-updates-model? state :input-text-changed) (update-model new-text)))))))
The channel value is pushed first and then the state gets updated. This has the theoretical potential of the data source kicking in first, then the on-change logic which can reorder the events and wipe the autocompletion state. I think the code needs to be reordered, but not sure if that will still be a guarantee, since I am not that familiar with the internal Reagent dispatching model.
So with this fix in place, the completion list stays on screen, but the moment you try to point your mouse at it or press an arrow to navigate, it performs a selection and closes down without any clicking involved.
What happens is this:
Mouse hovers or the user uses the arrow keys to navigate the completion list
activate-suggestion-by-index gets called
It updates the model based on the outcome of event-updates-model?, which returns (not change-on-blur?), so the model does get updated
component is redrawn, both external and internal models dont match - completion state is reset
A simple fix would be to change event-updates-model? to this:
And the final problem that I've hit is with the behavior of the ESC key, when :rigid? true - the input box gets cleared, but the model doesnt get reset. Relevant code:
(defn- reset-typeahead
[state]
(cond-> state
:always clear-suggestions
:always (assoc :waiting? false :input-text "" :displaying-suggestion? false)
(event-updates-model? state :input-text-changed) (update-model nil)))
Problem is reusing the :input-text-changed, which in this particular case doesnt count as a state resetting worthy event. I would suggest introducing another event and extending event-updates-model? accordingly to always clear down.
The text was updated successfully, but these errors were encountered:
I have the same problem. To be honest I spent several hours trying to figure out what I did wrong as I think this is the most basic usecase regarding the editing of a field.
Sorry if this reads as a disjointed rant - its not intended to be. Easiest thing for me is to do a PR with the "fixes" that seem right to me, but this is not my component, neither my library, so I would like to align my expectations with what the authors intended.
While the typeahead component looks fine in the demo, using it while wired to a model that is being updated makes me feel like a pig wrestling with a pumpkin :)
Consider the following oversimplified snippet:
Pretty standard affair - I have the component wired to a model and when the data changes - the model gets updated.
A side comment -
:change-on-blur?
is broken if you want to navigate with the mouse - the component only tracks theTAB
key as a method of losing the focus, so for users that like to click the:on-change
event never seems to be fired. So for my intents and purposes, I am going to set it tofalse
.The first problem that I've hit is with this piece of code which gets executed every time the component needs to be redrawn (for example, when the data source invokes the callback with a list of suggestions):
which invokes this function:
the function never updates the value for
:external-model
, so in effect every time the component is redrawn, its state wrt suggestions is reset. What happens visually, is that the completion list shows up then is immediately closed. The flow of events is like this:input-text-on-change!
gets invoked2.1. the key press is put on a channel that is going to trigger the data source (this smells as well, but more on it in a bit)
2.2. the
:model
gets updated with the valuestate
atom changesWith the fix above, on point 5 the autocompletion data wont get reset cause the
:external-model
and:model
will match.Note about point 2.1. - here is the
input-text-on-change!
code:The channel value is pushed first and then the state gets updated. This has the theoretical potential of the data source kicking in first, then the on-change logic which can reorder the events and wipe the autocompletion state. I think the code needs to be reordered, but not sure if that will still be a guarantee, since I am not that familiar with the internal Reagent dispatching model.
So with this fix in place, the completion list stays on screen, but the moment you try to point your mouse at it or press an arrow to navigate, it performs a selection and closes down without any clicking involved.
What happens is this:
activate-suggestion-by-index
gets calledevent-updates-model?
, which returns (not change-on-blur?), so the model does get updatedA simple fix would be to change
event-updates-model?
to this:And the final problem that I've hit is with the behavior of the
ESC
key, when:rigid? true
- the input box gets cleared, but the model doesnt get reset. Relevant code:Problem is reusing the
:input-text-changed
, which in this particular case doesnt count as a state resetting worthy event. I would suggest introducing another event and extendingevent-updates-model?
accordingly to always clear down.The text was updated successfully, but these errors were encountered: