29

I'm using react-hook-form for my input components, but there is one problem. In some text field, for example, text field for validation that take only number, i don't know how to do that, with normal textInput, we can use regex, like

 const [numberInput, setNumberInput] = useState("")
  function onTextChanged(value) {
    setNumberInput(value.replace(/[^0-9]/, "")) 
  }

and put that function and hook value on onTextChange and value respectively , i tried same method above on react-hook-form, but it won't work! i still can input other character like "+" or "-", of course using numeric keyboard

So here is TextField component

export interface HTextFieldProps extends TextFieldProps {
  control: Control<any>
  name: string
  defaultValue?: string
}

/**
 * Describe your component here
 */
export const HTextField = function HookformTextField(props: HTextFieldProps) {
  const { name, control, defaultValue = "", ...restProps } = props

  return (
    <Controller
      control={control}
      name={name}
      render={({ field: { onChange, value }, fieldState: { error } }) => (
        <TextField
          {...restProps}
          onChangeText={onChange}
          value={value}
          defaultValue={defaultValue}
          error={(error && error.message) as TxKeyPath}
        />
      )}
      defaultValue={defaultValue}
    />
  )
}

Here is when i use this

         <HTextField
            onChangeText={(value) => onTextChanged(value)}
            value={numberInput}
            name={"times"}
            control={control}
            autoCapitalize="none"
            keyboardType={Platform.OS === "android" ? "numeric" : "number-pad"}
            returnKeyType="done"
            inputStyle={INPUT_STYLE}
            required
          />

So how can i use only number in react-hook-form look like this, thank you a lots

6 Answers 6

47

Check the docs (V7): https://react-hook-form.com/api/useform/register

<input
  type="number"
  {...register("test", {
    valueAsNumber: true,
  })}
/>

If not using type="number"

<input
  {...register("test", {
    valueAsNumber: true,
    pattern:{
       value: /^(0|[1-9]\d*)(\.\d+)?$/
    },
  })}
/>

You can still use validate.

<input
  {...register("test", {
    valueAsNumber: true,
    validate: (value) => value > 0,
  })}
/>
Sign up to request clarification or add additional context in comments.

3 Comments

why one has to add { valueAsNumber: true } is beyond when the type is specified as number in often more than one place already? But this worked for me and got me passed 48 hours of being blocked!
stackoverflow.com/questions/35791767/… this one may help people to understand a little further that @AdamE
Fixed docs link: https://www.react-hook-form.com/api/useform/register/ (needs trailing slash)
9

this work for me

<Controller
    control={form.control}
    name="milhas"
    render={({ field }) => {
        return ( <input type="number"
                   {...field} 
                   onChange={(value) =>
                   field.onChange(value.target.valueAsNumber)
                }
                 />
             )
          }}
</Controller>

Comments

6

Solution for integers only

You can just set <TextField /> prop type to number and then there will be only numbers allowed.

<Controller
  control={control}
  name={name}
  render={({ field: { onChange, value }, fieldState: { error } }) => (
    <TextField
      {...restProps}
      onChange={onChange}
      value={value}
      fullWidth
      label="Times"
      defaultValue={defaultValue}
      type="number"
      error={error && error.message}
    />
  )}
  defaultValue={defaultValue}
/>

Edit React Hook Form - Typescript (forked)

Solution for leading zeros or exponent

As noted in the comments here is a version accepting also leading zeros or exponent notation by using RHF's validate function.

const validate = (value: string) => {
  const matches = value.match(
    /^(?:0\.(?:0[0-9]|[0-9]\d?)|[0-9]\d*(?:\.\d{1,2})?)(?:e[+-]?\d+)?$/
  );
  return matches?.length > 0 || "Not a Number";
};

return (
  <Controller
    control={control}
    name={name}
    rules={{ validate }}
    render={({ field: { onChange, value }, fieldState: { error } }) => (
      <TextField
        {...restProps}
        onChange={onChange}
        value={value}
        fullWidth
        label="Times"
        error={!!error}
      />
    )}
    defaultValue={defaultValue}
  />
);

Edit React Hook Form - Typescript (forked)

7 Comments

But can i use this on react-native?
Yes, you can. Do you need to support decimals as well or only integer values?
Thanks, no, it accept only number for 6 number validation 😁
This works unless you need to have leading zeroes included. type='number' strips leading zeroes as input value is considered a number.
Your solution does not work when you press the e character.
|
6

Using react-hook-form v7 this is working for me:

<input {...register('age', {
    pattern: {
        value: /^[0-9]+$/,
        message: 'Please enter a number',
    },
})} />

Comments

5

use something liket this

const allowOnlyNumber=(value)=>{
   return value.replace(/[^0-9]/g, '')
}

return (
    <Controller
      control={control}
      name={name}
      render={({ field: { onChange, value }, fieldState: { error } }) => (
        <TextField
          {...restProps}
          onChangeText={(text)=>onChange(allowOnlyNumber(text))}
          value={value}
          defaultValue={defaultValue}
          error={(error && error.message) as TxKeyPath}
        />
      )}
      defaultValue={defaultValue}
    />
  )

1 Comment

thank for your answer, but unfortunately , i can't input any number after doing this, maybe it require onChange
0

Little late to the party, but I did this.

              <Controller
                  control={control}
                  {...register(`userPreferredStakes.${x}.prefStake`)}
                  name={`userPreferredStakes.${x}.prefStake`}
                  render={({ field: { onChange, onBlur, value } }) => (
                    <TextField
                     id="standard-basic" 
                     placeholder="Stake(£)" 
                     variant="standard"
                     type='number' 
                     value={getValues(`userPreferredStakes.${x}.prefStake`)} 
                     onChange={(e) => onChange(+e.target.value)}
                    />
                  )}
                />

Note: type='number' & onChange={(e) => onChange(+e.target.value)}` allows me to save the item, and when logging the saved data I get the following.

userPreferredStakes:Array(13)
0:{oddsLow: 0, oddsHigh: 2, prefStake: 300}
1: {oddsLow: 2.01, oddsHigh: 3, prefStake: 200}
  ....

whereas not adding the + within onChange I would have gotten

userPreferredStakes:Array(13)
0:{oddsLow: 0, oddsHigh: 2, prefStake: '300'}
1: {oddsLow: 2.01, oddsHigh: 3, prefStake: '200'}
  ....

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.