Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

keep input-cursor position between patches? #10

Closed
zaceno opened this issue Apr 18, 2018 · 5 comments
Closed

keep input-cursor position between patches? #10

zaceno opened this issue Apr 18, 2018 · 5 comments

Comments

@zaceno
Copy link

zaceno commented Apr 18, 2018

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?

@yelouafi
Copy link
Owner

yelouafi commented Apr 19, 2018

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

petit-dom/src/vdom.js

Lines 124 to 126 in 5412b18

if (oldv !== newv) {
el[key] = newv;
}
.

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

const DELAYED_PROPS = { selected: true, value: true, checked: true };

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.

@cjh9
Copy link

cjh9 commented Apr 19, 2018

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...

@zaceno
Copy link
Author

zaceno commented Apr 19, 2018

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 )

@cjh9
Copy link

cjh9 commented Apr 20, 2018

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 😂

@zaceno
Copy link
Author

zaceno commented Apr 20, 2018

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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants