Constraining input element not working
I want to constraint the values of some input element but I seem to have a misunderstanding of the update cycle of solid.
Example:
The value displayed in the div is constrained to 5 characters but in the input itself I can keep writing as long as I want. What I noticed is that this behavior changes depending on whether the cursor in the input is at the end or somewhere else. If it is not at the end it is correctly clipped.
Can someone explain this behavior? I would have expected that the input gets its updated value from the signal after the
oninput
handler ran.11 Replies
your logic doesn't restrict what can be written to the input
only what ends up in the signal
and because signals do an equality check before triggering updates, assigning it to the same value will not trigger the input to update it's value
If you have a string
"hello"
in the signal and add "!"
to it, the trimmed string will still be "hello"
, so the signal will ignore that change.
You can disable that behavior with { equals: false }
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Thanks this explains the behavior!
Also, maxlength is supported by HTML: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/maxlength
HTML attribute: maxlength - HTML: HyperText Markup Language | MDN
The maxlength attribute defines the maximum number of characters (as UTF-16 code units) the user can enter into an or . This must be an integer value 0 or higher.
If you want to constrain it even more, I wrote our input-mask-primitive for that exact use case: https://github.com/solidjs-community/solid-primitives/tree/main/packages/input-mask
GitHub
solid-primitives/packages/input-mask at main · solidjs-community/so...
A library of high-quality primitives that extend SolidJS reactivity. - solid-primitives/packages/input-mask at main · solidjs-community/solid-primitives
Thanks! Yes actually the substring was just an example. I want to constraint it to decimal values but the interaction is a bit confusing for me. I guess my issue before was that I tried to constraint the value set to the signal but not the actual input value.
Actually I tried to use your library yesterday (edit: nvm it was another one) ! What confused me a bit was that my data model is
number | undefined
and removing the last character in the input resulted in a value of 0
. I have found this behavior in the issue tracker of the project where someone (you?) mentioned to customize the mask implementation. But I could not wrap my head around it - Maybe I should check again.
This seems such an easy task but somehow I am approaching it the wrong way.I really need to improve the documentation of that primitive. What is it you want to achieve?
Basically just a way to enter a
number|undefined
and prevent anything else from appearing in the input.
Just to demonstrate the idea - Something like this: https://playground.solidjs.com/anonymous/683f3062-099c-46d8-b057-9f6501ba1c02
Requiring the consumer of the component to use { equals: false }
doesn't sound very clean. And if the input state is 123
adding a .
does not work because it is directly overwritten by the model value.
I thought about implementing this as a directive instead - So the constraint handling does not happen on the signal. Does this make sense?Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Is undefined the empty default or do you require your user to input "undefined"?
In the former case, you could just use
const numMask = createInputMask([/\d+/])
to remove any non-number inputs, then use the following event handler to fill your signal:
Yes the
undefined
is the empty case. You example works for integer values but not if there is a fractional part. It gets more complicated with the latter because there are intermediate inputs which are not completely valid 123.
is fine while inputting text but should become 123
when leaving focus.
Better example: https://playground.solidjs.com/anonymous/3c92f707-e386-4778-a2a0-f97ea5e9029d
But even with this example the behavior is weird because of the interaction with the signal. If the input value is 123.1
and the user removes the last character, the input becomes 123
instead of 123.
. Thanks to the first answer in this thread I understand why this is the case but it is not ideal from a UX perspective.Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
In that case, you want two masks: one for the input event that allows ending a number with "." (
[/\d+(\.\d*|)/]
), and another one for the change event that disallows that case (exchange the last asterisk with a plus).