keep input-cursor position between patches?
zaceno opened this issue · comments
Please see this example on codepen: https://codepen.io/zaceno/pen/BxaENr?editors=0010
I'm rendering a plain text-input, and expect to capture the value every oninput
. Each time I update (patch) the ui. (A quite normal scenario, I think. For every input, you want to do some validation, helpful formatting, et c. Hence: update the ui).
It works fine except when you try to enter something in the middle or beginning of the input. In that case, the cursor jumps to the end of the input. Not entirely unexpected, since I'm rerendering and the previous cursor position isn't kept track of anywhere.
So, I could correct for this by using a custom component class where I can store the cursor position in the component state between renders. But that seems like overkill for something so trivial.
Is there some simpler way I could handle this, so I can still use a plain h('input', {...})
without making a component? If not, may I suggest keeping track of cursor position as a feature-request?
I wasn't able to reproduce the issue with the above example.
Since this line oninput: ev => setValue(ev.target.value)
just sets the state value to the one already existing on the DOM input, the library will skip updating the DOM input (since in this case they are the same). See
Lines 124 to 126 in 5412b18
So as long as the state value is equal to the DOM input value, the lib will not touch the DOM (so cursor jumps shouldn't occur here)
However I can reproduce the issue by setting the state value to something else than the one currently in the DOM input. For example
function setValue(x) {
value = x + "o"
/*
In a real application, capturing the input
might lead to validation or other reasons
to update the ui. So we do:
*/
updateUI()
}
In this case effectively the lib will change the DOM input value which causes the cursor position to jump to the end.
may I suggest keeping track of cursor position as a feature-request?
Yes of course, but (for the reasons below) I'd prefer to do this in the same way the lib is managing other interactive props (like 'value', 'checked'...). It keeps a map of those props here
Line 4 in 5412b18
And those props are updated after attributes
We can simply add selectionStart
and selectionEnd
to that list; and let the developer choose if he wants to keep track of the cursor position on the state.
(A quite normal scenario, I think. For every input, you want to do some validation, helpful formatting, et c. Hence: update the ui).
IMHO I'm not really sure it's a good idea to change the DOM input value while the user is currently typing it. Sure I understand that we would like for example to format a numeric value, but this formatting typically should occur after the user has finished typing (e.g. blur event) to avoid any interference with the user typing process.
I'm not also sure restoring cursor position between updates will be sufficient to solve the UX issue. For example, formatting the numeric value while the user is typing, keeping the cursor position can lead to weird UX issues. Here is a forked example (https://codepen.io/anon/pen/KRwWdr?editors=0010) that restores the cursor position after each update : try typing '123' then observe what happens when typing '4'.
But perhaps there maybe some cases I didn't think of where this could be useful.
It works fine except when you try to enter something in the middle or beginning of the input. In that case, the cursor jumps to the end of the input.
I'm not able to reproduce this either...
Hmm... guess what: in Chrome, I can't reproduce it either 😅 . Go figure. I was working in Safari when I noticed it and never bothered to check other browsers.... I wonder what the difference could be? Works fine in Firefox too btw.
@yelouafi Thank you for the thoughtful response! Your explanation makes sense. It should just work - and clearly does in most cases 🤷♂️. So I withdraw my feature request :)
Still... I wonder what's up with Safari?!
(It might not even be Safari-specific. I've noticed sometimes codepens on Safari exibit behavior that is not seen when the same code is run in a standalone web-page in Safari ... I should test that )
I just tried with IOS 11, the bug is both on Safari and Chrome (the later is just using a webview) But then I tried to upgrade to IOS 11.3 and the upgrade failed so I have to restore with Itunes. To bad my mac only has USB C ports. The day starts well 😂
I've been able to confirm that it is not codepen related. The problem appears even when the script is loaded from a plain html page. Also, I disabled babel. same thing. All in Safari only (so far. Haven't been able to try Edge or IE11)