modular-forms icon indicating copy to clipboard operation
modular-forms copied to clipboard

Select component with number types

Open PHinett2 opened this issue 1 year ago • 4 comments

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?

PHinett2 avatar Feb 14 '24 00:02 PHinett2

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.

fabian-hiller avatar Feb 14 '24 01:02 fabian-hiller

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.

PHinett2 avatar Feb 14 '24 12:02 PHinett2

If you are using Zod or Valibot to validate your form, you could use transform to transform the strings to numbers.

fabian-hiller avatar Feb 14 '24 14:02 fabian-hiller

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.

floratmin avatar Sep 02 '24 10:09 floratmin