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

Unable to apply under decimal started by 0 with <NumberInput /> on mobile devices #8593

Closed
Seojun-Park opened this issue Jan 20, 2023 · 3 comments · Fixed by #8610
Closed

Comments

@Seojun-Park
Copy link
Contributor

Seojun-Park commented Jan 20, 2023

What you were expecting:
I would like to submit value 0.001 with <NumberInput />.
On PC, It works with comma not point such as 0,001, but it doesn't work on mobile device especially IOS.
(I tested with iPhone13 pro, Safari and Chrome)

As a workaround I found, is to override the format prop as (value) => value.

What happened instead:
The value on the input sets to 0

Steps to reproduce:

Code sandbox : https://codesandbox.io/s/lucid-fast-8b9lxg?file=/src/posts/PostCreate.tsx

PC

  1. Go to Post create page
  2. Give 0.0** to the <NumberInput /> on the page.

Mobile (IOS, android partially)

  1. Go to Post create page
  2. Give 0.0** or 0.0** to the <NumberInput /> on the page.

Related code:

Other information:

For this function, I assume 0.0.toString() case should be considered as well, because this function can be executed during typing number

const convertNumberToString = value =>
    value == null || isNaN(value) ? '' : value.toString();

Environment

  • React-admin version: ^4.6.3
  • Last version that did not exhibit the issue (if applicable):
  • React version: v17
  • Browser: IOS (Safari, chrome), Android(chrome)
@slax57 slax57 added the bug label Jan 23, 2023
@slax57
Copy link
Contributor

slax57 commented Jan 23, 2023

Reproduced, thanks!

@slax57
Copy link
Contributor

slax57 commented Jan 27, 2023

Okay, so I took some time to dig into this, but the issue is way more bushy than I anticipated.

Root of the issue:
The NumberInput component has to manage two states:

  • A React (controlled) state, representing the input value in the DOM
  • A form state, managed via react-hook-form, representing the value in the record

We need to sync these states both ways:

  • When the user types in a number, the form state needs to be updated with the parsed value
  • When the form value changes (e.g. after the record has been fetched, or if an event changes the form state value e.g. with setValue), the react state needs to be updated with the formatted value

This is the root of the issue, because when the user types in 0.0, it gets parsed to 0 and then the react state (value visible in the DOM) will be updated to 0 as well, hence erasing the user input.

Why is it different on mobile
Actually it's not. It's different because of the browser.

  • Chrome considers that 0, is a valid (albeit incomplete) number value, and as such will not trigger the onChange event yet. It waits for the next character to trigger it.
  • Chrome considers that 0. is not a valid number value, and hence calls the onChange event with a value of '' (yes, an empty string!)
  • Safari considers both values 0, and 0. to be invalid, and hence calls onChange with '' for both inputs

What's blocking me from fixing the issue

  • I can't find a reliable way to detect that the input is in a transitory state like 0, or 0., because the browser sends the same value as when the input is empty
  • I can't find a way to avoid erasing the user input with the parsed value when it's in a transitory state, without loosing the reactive ability of the field
  • I don't want to turn the <input type="number"> to an <input type="text"> because it would loose the benefits of being a number field, especially on mobile browsers
  • I don't want to only parse the input on Blur, for the reasons explained here
  • I don't want to debounce the parsing of the input, because it would only move the issue a bit further away without really fixing it, and this behaviour might lead to unexpected and unintuitive results

So basically I'm out of ideas about how to solve this issue. 🙁

If anyone can help us finding a solution for this one, we'd be grateful! 🙏

@fzaninotto
Copy link
Member

I suggest we add a test in the useEffect that reacts to the form state change, to skip the effect if the input is focused. This should be based on a ref that is set to true onFocus and to false onBlur.

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