0

I am new to TypeScript and currently I am designing a BMR calculator. I have created a handleNumericInput function that only allows numbers to be accepted inside an input box but the problem is when I type a non-numeric character inside, it will either return NaN or clear the field entirely (depending on how I have set the value for each input). I just want it to not be typed at all. Here is my code:

App.tsx:

// Defined measurements and states
const [metricMeasurement, setMetricMeasurement] = useState<Metric>({
    heightInCentimetres: 0,
    weightInKilos: 0,
    age: 0,
  });

  // US measurement state
  const [usMeasurement, setUsMeasurement] = useState<US>({
    heightInFeet: 0,
    heightInInches: 0,
    weightInPounds: 0,
    age: 0
  });

// handleNumericInput function
const handleNumericInput = (e: React.ChangeEvent<HTMLInputElement>,
    measurementType: "metric" | "us"
  ) => {
    const { name, value } = e.target;
    if (/^\d*\.?\d*$/.test(value)) {
      measurementType === "metric" ? 
      setMetricMeasurement((prev) => ({ ...prev, [name]: Number(value) })) :
      setUsMeasurement((prev) => ({ ...prev, [name]: Number(value)}))
    } else {
      setMetricMeasurement((prev) => ({ ...prev, [name]: "" }))
      setUsMeasurement((prev) => ({ ...prev, [name]: "" }))
    }
  };

Metric.tsx:

<input 
  className='m-3 bg-slate-100 border w-full h-10 border-slate-300 rounded pl-1' 
  placeholder="cm"
  inputMode="numeric"
  type='text'
  pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}"
  value={metricMeasurement.heightInCentimetres || ''}
  name="heightInCentimetres"
  onChange={(e) => {
    setMetricMeasurement({
      ...metricMeasurement,
      heightInCentimetres: Number(e.target.value)
    });
    handleNumericInput(e, "metric");
  }}
/>

If i use value={metricMeasurement.heightInCentimetres || ''} and type a non-numeric character, it clears the field but if I just use value={metricMeasurement.heightInCentimetres} and type a non-numeric character, it returns NaN.

And yes, I am aware that you can use type="number" to only allow numbers to be typed. I have set to text to allow placeholders to define measurement types. Any help will be appreciated.

0

1 Answer 1

1

You're updating the state in two places. I think you should remove one from onChange and update it only if the input is numeric:

<input 
  className='m-3 bg-slate-100 border w-full h-10 border-slate-300 rounded pl-1' 
  placeholder="cm"
  inputMode="numeric"
  type='text'
  pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}"
  value={metricMeasurement.heightInCentimetres || ''}
  name="heightInCentimetres"
  onChange={(e) => handleNumericInput(e, "metric")}
/>
const handleNumericInput = (e: React.ChangeEvent<HTMLInputElement>,
    measurementType: "metric" | "us"
  ) => {
    const { name, value } = e.target;
    if (/^\d*\.?\d*$/.test(value)) {
      if (measurementType === "metric") { 
        setMetricMeasurement((prev) => ({ ...prev, [name]: Number(value) }))
      } else {
        setUsMeasurement((prev) => ({ ...prev, [name]: Number(value)}))
      }
    }
  };
Sign up to request clarification or add additional context in comments.

1 Comment

So simple and completely missed it. Thank you.

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.