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

Behaviour is not exactly like the native input[type='number'] #56

Open
V-ed opened this issue Nov 16, 2019 · 10 comments
Open

Behaviour is not exactly like the native input[type='number'] #56

V-ed opened this issue Nov 16, 2019 · 10 comments
Labels
enhancement New feature or request

Comments

@V-ed
Copy link
Contributor

V-ed commented Nov 16, 2019

For a quick test, simply set data-step="2", set the value to 5, and try to decrement : expected 3, got 2. You can also do this test in your live demo in your "Dynamically handling of min, max, step and data-decimals" section (sidenote : would be nice if there was ids to your page sections, so we could link them directly in links!).

Same goes with increment, incrementing an odd number by an even number does not give the expected result (with the last example, I would expect 5 + 2 = 7, but 8 is currently being produced).

I realized that by doing some tests on my own fork, and tracing back I found that you changed to a rounding logic in this commit : be6b7c8, and now I'm wondering what is that "better form handling".

A fix for this would be to change this line :

setValue(Math.round(value / step) * step + step)

to :

setValue(value + step)

... but I figure there was an issue to doing simply that, as this is what you had previously... so here's an issue to discuss about it :)

@shaack
Copy link
Owner

shaack commented Nov 17, 2019

The setValue(Math.round(value / step) * step + step) is to reconstruct the behaviour of the standard (native) input type="number". The standard input type="number" steps to to values min + n * step. The input-spinner steps to values n * step.

@shaack
Copy link
Owner

shaack commented Nov 17, 2019

setValue(value + step) is not working like the native input type="number". Just make a HTML page an try it. Take a look at the specification: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number "Note: When the data entered by the user doesn't adhere to the stepping configuration, the user agent may round to the nearest valid value, preferring numbers in the positive direction when there are two equally close options."

@shaack
Copy link
Owner

shaack commented Nov 17, 2019

In my opinion the correct behaviour is not, that ist should step to value + step, but it should step to the next min + n * step from value + step and currently it is stepping to the next n * step from value + step.

@V-ed
Copy link
Contributor Author

V-ed commented Nov 17, 2019

Interesting, but if I read the specs correctly with the quote you added (I also added it just below), I think doing value + step would still be valid with that definition :

Note: When the data entered by the user doesn't adhere to the stepping configuration, the user agent may round to the nearest valid value, preferring numbers in the positive direction when there are two equally close options.

The key here is the beginning : When the data entered by the user. This does refer to the steps, but rather when the value entered by the user is not in a valid step range. Ex.: Value is 1, step is 10, the valid range is therefore (with a min of let's say 0) : [1, 11, 21, 31, 41, 51, 61, ...]

In the example above, entering manually 4 would "round" the value to 1, because that's the closest to the stepping range. If the manually entered value is 10, it would "round" to 11. The ambiguity would be when the user enters 6, as this value is equally distant from 1 and 11 (5 from both) : it would therefore prefer to round up (key in the quote : preferring numbers in the positive direction), going then to 11.

While this logic would be good to implement in the setValue method, I don't think it should be in the calcStep method, as the calcStep is to calculate how much of a step it needs when using the buttons, and to dispatch the events (well, in the current version of your library, at least).

EDIT : As the quote says, "the user agent may round to the nearest valid value" : in chrome, this is not what happens ; instead, it allows the value, but when submitting a form, it will not pass validation, providing a message saying something like "The nearest valid values are 1 and 11". The browser really dictates this behavior, but IMO, I would prefer that it round automatically.

@shaack
Copy link
Owner

shaack commented Nov 18, 2019

Okay, but wee agree, that it should work like the native spinner, or not? I created a test page for this with different parameters: https://shaack.com/projekte/bootstrap-input-spinner/test-native.html
So the question is, how to accomplish, that it works like that?

@V-ed
Copy link
Contributor Author

V-ed commented Nov 18, 2019

Oh, I completely agree that it should work like the native spinner! Although I added in my latest edit that it is also broswer (well, user-agent...) dependant, so unless you want to add a check for the user-agent and implement the logic of every browser, I think we should agree on what would be the best default behavior "of a native spinner".

I don't especially like how Chrome does it : if a user enters a value manually, that value is validated only on form submit - wouldn't it be better if the validation happens when the user entered a value?
I guess that this could confuse the user a bit if he entered a number and another one would appear, because as an example his 6 is not in the valid range of steps I described in the previous comment... What do you think?
Try entering 12 manually in your third input on your test page (with step 20 and min -99), what do you see? In Chrome, it allows me entering 12, but if I mouse over (if I hover) the input, it tells me (in my browser language) that Please enter a valid value. The two closest valid values are "1" and "21"..
This would also be the message shown as a validation error in a form if I were to submit this...

With all I said above, I'm trying to think of what would be the default behavior if you entered then 4 in the input : in a way, the value 4 is not in a valid range of your third input (steps are [... , -19, 1, 21, 41, 61, ...], so it should not be accepted, but should it be directly changed to the nearest valid value? I'm now not sure, maybe the user wanted to input 41, but had to type 4 to get to 41...

With that said, the default should probably be to test only for the value on form submit? If so, we could simply use the setCustomValidity method (quick link) and not change the value shown on screen, and let the user change it manually if it's not valid (and setting a custom validity message sayin what chrome says).
In that case, the increment and decrement buttons should automatically go to the nearest valid value (in my example with [... , -19, 1, 21, 41, 61, ...], if user has manually entered 4, using the increment button should go to 21). Also, when the value is valid, simply changing the custom validity message to an empty string would mark the input to be valid.
This issue I see with this is that setting a custom validity message would mean making it locale dependant, so I'm wondering if there's a way to capture the one that chrome / other browsers gives automatically based on browser locale... or the configured locale... would it be with an hidden number input? but then, how would your locale configuration affect this string...

What do you think?

@V-ed
Copy link
Contributor Author

V-ed commented Dec 18, 2019

With the removal of the config.locale option, I believe it would be possible to implement this validation based on Chrome's behavior :

On changing value manually (not with the buttons), your plugin would check the validity and if it isn't, we would use the setCustomValidity method to set the validity message of the generated input, using the validation message from the original input.

I've searched a bit and there is the validation message as a property in the javascript's object : $original[0].validationMessage.

If I based this on Chrome's behavior, this would mean that bad manual inputs stays as is in the input, but gets invalidated (so forms would show the validation message on submit) : the value wouldn't change when typing it / losing focus. Using the buttons would jump to the nearest value in the direction of the button.

I could draft an implementation of this, but doing it as Chrome does means that while it is based on a majority of the user base, there might be edge cases where some users may feels like not really native (for example, if Opera actually handles these inputs between steps and rounds them when losing the focus of the input, then my suggestion's implementation will be a bit different. this is an example, I don't know how Opera handles it, probably the same as Chrome as Opera is Chrome based).

@shaack would it be an accepted default?

@shaack shaack changed the title Incorrect rounding of even steps on odd values Behaviour is not exactly like the native input[type='number'] Jul 30, 2020
@shaack
Copy link
Owner

shaack commented Sep 13, 2020

Should work as described here: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number#step

Should implement:

"Only values which are equal to the basis for stepping (min if specified, value otherwise, and an appropriate default value if neither of those is provided) are valid."

and

"Note: When the data entered by the user doesn't adhere to the stepping configuration, the user agent may round to the nearest valid value, preferring numbers in the positive direction when there are two equally close options."

@shaack shaack added the enhancement New feature or request label Sep 13, 2020
@V-ed
Copy link
Contributor Author

V-ed commented Sep 14, 2020

The issue is still there :

"Note: When the data entered by the user doesn't adhere to the stepping configuration, the user agent may round to the nearest valid value, preferring numbers in the positive direction when there are two equally close options."

the user agent MAY round to the nearest valid value

The issue I had was about, for example, Chrome implementing the rounding, while Safari wouldn't.

I didn't do an exhaustive list of which browsers (read: user agent) implement the stepping mechanism in the way Chrome does or not, but the issue is that if you want to have a spinner that behaves natively, you'll need to do user agent checks and implements all the different implementations of these different user agents.

Obviously, you could go for the route of implementing the way Chrome does it, and force it out like so, maybe even implement no rounding as well and add a config option so developers who uses your spinner will have the choice - there's many things you could do, but a decision needs to be made here :

  1. Implement it the way Chrome does it : validate data on form submit, but using the buttons, only valid numbers are stepped through;
  2. Implement an option to round if manual bad data is entered, with potential error prone issues (read the third paragraph)
    • A way to mitigate bad rounding on enter would be to add some debouncing to the check...
  3. Search through all the ways different user agents do it, and implement all their different implementations, grouping those who are similar, and add checks to set the correct behavior for stepping

Some of those options require more job than the others, and I don't want to be the judge of this : I think I'd rather do one consistent behavior for the plugin, but having a native feel for the spinner is interesting too, so I'm torn between those options...

@shaack
Copy link
Owner

shaack commented Sep 14, 2020

Yes, many thanks for the summary. I think it should behave like native, like the Chrome browser.
Testpage: https://shaack.com/projekte/bootstrap-input-spinner/test-native.html

@shaack shaack mentioned this issue Apr 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants