modular-forms
modular-forms copied to clipboard
Select component with number types
I have been trying to modify the Select component from the playground to accept number or number[] values in both the value and options props, but i can't seem to get it to work unless I use strings for everything.
Is there a limitation that it must be string values, or could there be a way to allow number types too?
I think the main problem here is that HTML <select />
element does not allow us to capture values as numbers, only as strings. That's why Modular Forms probably doesn't do it either.
Yes i presumed this was the case. I can work with this i suppose. Its just that i would need to convert the values back to number types before submitting them back to my rest api.
If you are using Zod or Valibot to validate your form, you could use transform
to transform the strings to numbers.
I got it to work with Kobalte NumberField:
import { createSignal, JSX, Show, splitProps } from 'solid-js';
import { NumberField } from "@kobalte/core/number-field";
import styles from './ModularFormNumberField.module.css';
import { ArrowUp, ArrowDown, InputErrorMessage } from '@workspace/app-elements';
export type NumberFieldProps = {
name: string;
label?: string | undefined;
placeholder?: string | undefined;
incrementLabel: string;
decrementLabel: string;
value: number | undefined;
error: string;
formatOptions?: Intl.NumberFormatOptions;
displayErrorMessage: boolean;
description?: string | undefined;
required?: boolean | undefined;
disabled?: boolean | undefined;
autofocus?: boolean | undefined;
ref: (element: HTMLInputElement | HTMLTextAreaElement) => void;
onInput: JSX.EventHandler<HTMLInputElement | HTMLTextAreaElement, InputEvent>;
onChange: JSX.EventHandler<HTMLInputElement | HTMLTextAreaElement, Event>;
onBlur: JSX.EventHandler<HTMLInputElement | HTMLTextAreaElement, FocusEvent>;
setValue: (value: number | undefined) => void;
};
export function ModularFormNumberField(props: NumberFieldProps) {
const [rootProps, inputProps, errorProps] = splitProps(
props,
['required', 'disabled', 'formatOptions'],
['name', 'placeholder', 'autofocus', 'ref', 'onInput', 'onChange', 'onBlur'],
['error', 'displayErrorMessage'],
);
return (
<NumberField
{...rootProps}
rawValue={props.value}
onRawValueChange={props.setValue}
class={styles.numberField}
validationState={props.error ? 'invalid' : 'valid'}
>
<Show when={props.label}>
<NumberField.Label class={styles.numberFieldLabel}>{props.label}</NumberField.Label>
</Show>
<div class={styles.numberFieldGroup}>
<NumberField.Input {...inputProps} class={styles.numberFieldInput} />
<NumberField.IncrementTrigger aria-label={props.incrementLabel} class={styles.numberFieldIncrement}>
<ArrowUp class={styles.icon} />
</NumberField.IncrementTrigger>
<NumberField.DecrementTrigger aria-label={props.decrementLabel} class={styles.numberFieldDecrement}>
<ArrowDown class={styles.icon} />
</NumberField.DecrementTrigger>
</div>
<Show when={props.description}>
<NumberField.Description class={styles.numberFieldDescription}>{props.description}</NumberField.Description>
</Show>
<InputErrorMessage {...errorProps} component={NumberField.ErrorMessage} />
</NumberField>
);
}
and calling it with:
<ModularFormNumberField {...mergeProps(fieldProps, props.component, {value: field.value, error: field.error, setValue: (value: number) => setValue(props.formStore, props.component.name, value)}) as NumberFieldProps} />
The only problem is that when the number field is optional, then NaN
is returned. It looks like that the function setValue
tries to convert undefined to a number. So I have to remove fields with NaN
manually when submitting the form.