Handling defaultValues for a required number field
I know this is more of a general React issue than a TF-specific one, but I didn’t run into it with RHF since they don’t use controlled components by default.
I have a required amount field that should be a number. If I use z.number(), I run into the default value issue—I don’t want 0 (bad UX), "" isn’t assignable to number, and undefined causes React’s controlled/uncontrolled warning.
Would it be better to keep it as a string (""), then parse it before submission? Or is there a cleaner approach?
22 Replies
genetic-orange•6mo ago
z.coerce.number() can cause NaN if the string is empty, so that isn‘t really cleaner. Is there a reason why 0 shouldn‘t be the default value if you want the field to be required?
sunny-greenOP•6mo ago
Yes exactly, I have a lot of amount inputs in my app, setting the default value as 0 requires the user to delete everytime before entering the new value, and it is not ideal for my UX
fair-rose•6mo ago
@Mohamed Yahye El Joud
Try the following:
Add this reusable piece to your codebase:
Now to use it:
z.input will infer to string and z.output will infer to number!
This is how we do it on our codebase. The main annoying part is that you still need to coerce to number. There might be a way to have the base scehma coerce but I'm not sure how.
rival-black•6mo ago
Do you use this in a text or number input? Asking because I wanna do something like that but dont allow the user to write letters if its number input field
fair-rose•6mo ago
I use it in an input with type text, however I use react-number-format to limit what the user can type.
conscious-sapphire•6mo ago
I have a similar use case where I have a number field that is not required and I don't want an initial value. Is there an elegant way to solve this? What I think I truly want is nullable fields but that doesn't seem to play nice with controlled inputs
fair-rose•6mo ago
You want to set a number field initially to null?
conscious-sapphire•6mo ago
or
undefined
yes. It is an optional field
I have the same issue with optional string
fields as well. I don't want to save empty strings to my DBfair-rose•6mo ago
Got it!
would something like this work:
z.input would infer to number | null (allowing you to initiate as null)
z.output would infer to number
conscious-sapphire•6mo ago
but i don't want it to be required
genetic-orange•6mo ago
perhaps transform can turn empty trimmed strings into null
and when setting the input‘s value, you fall back to ?? „“
conscious-sapphire•6mo ago
transform()
doesn't do anything in validator schemas from what I've seengenetic-orange•6mo ago
(mobile coding :Sadge: )
fair-rose•6mo ago
So why is z.number().optional() not okay? Sorry not sure what I'm missing.
genetic-orange•6mo ago
I think the issue is that html controlled inputs shouldn‘t receive null
so the question is how should that be handled
fair-rose•6mo ago
Ahh true true, sorry since our team always initiates fields in forms as empty strings (except for like select) fields, we don't run into that issue.
I'd agree with you Luca, if you MUST initiate with null, you'd have to cast the value prop ?? "". At least I'm not sure of another way now.
genetic-orange•6mo ago
number inputs are terrible in general to handle. On Firefox, I noticed that inputs of type number don‘t trigger onChange if the value is NaN
conscious-sapphire•6mo ago
Yeah I still can get by with all string inputs but that leads to other pain when trying to replace all the empty strings of optional fields with
null
genetic-orange•6mo ago
what about doing that transform from empty string to null before passing it to handleChange?
conscious-sapphire•6mo ago
are you saying like this?
genetic-orange•6mo ago
yeah, but I haven‘t tested it. Of course it implies that the state value can be undefined, so a nullish coalescer to an empty string is also required
conscious-sapphire•6mo ago
i had to add
| undefined
here
const field = useFieldContext<string | undefined>();
it works but i still get a Type 'string' is not assignable to type 'undefined'
TS error for onSubmit
unless i add as z.input<typeof FormSchema>
to my defaultValues
object
the undefined
default value works fine even without the handleChange change up above
it just causes TS errors unless you type cast your defaultValues
I'll have to revisit this with a fresh mind tomorrow, tried a ton of things and couldn't get a nice solution