Home > Back-end >  React Material UI TextField type=number onStepChange analog?
React Material UI TextField type=number onStepChange analog?

Time:08-18

I building a React component using Mui TextField. Its a number field so there are two ways to update the TextField component: Editing the text itself and using the step arrows. When "blurring" the field, I want to snap the value to the nearest multiple of 5. I also set the step="5" as well.

The component itself has an onChange event that passes the number value but I only want this event to fire when the user "steps" the value or the user "blurs" the field. Here's what I've got so far:

interface WeightFieldProps {
  name?: string
  placeholder?: string
  label?: string
  value?: number
  onChange?: (value: number) => void
}

const WeightField: React.FC<WeightFieldProps> = ({
  name,
  placeholder,
  label,
  value = 0,
  onChange
}) => {
  const [weight, setWeight] = useState(value)
  
  // Update the component but do not fire the parent onChange event.
  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const value = parseInt(event.target.value)
    setWeight(value)
  }
  
  // Update the component as usual but notify the parent component that
  // the value has changed.
  const handleBlur = (event: React.FocusEvent<HTMLInputElement>) => {
    const value = snapWeightValue(parseInt(event.target.value))
    setWeight(value)
    if (onChange) onChange(value)
  }
  
  // Ideally, I want the parent component only be notified when the user
  // is changing the input value via the step arrows.
  // const handleStepChange = (event: React.SomeEvent) => {
  //   const value = parseInt(event.target.value)
  //   setWeight(value)
  //   if (onChange) onChange(value)
  // }

  return <TextField
    name={name}
    type="number"
    placeholder={placeholder}
    label={label}
    InputProps={{
      endAdornment: <InputAdornment position="end">lbs</InputAdornment>
    }}
    inputProps={{
      step: "5",
      style: {
        fontSize: "2em",
        padding: "10px",
        textAlign: "right"
      }
    }}
    value={weight}
    onChange={handleChange}
    onBlur={handleBlur}
    // onStepChange={handleStepChange}
    fullWidth
  />
}

What I'm hoping for is some kind of event handler specifically for when a user updates the field via the numeric step buttons or maybe a way to determine how the field is being updated during the onChange event so I can fire the component's onChange event only when the user is stepping the value?

CodePudding user response:

I would suggest hiding the native arrow buttons, adding custom arrow buttons like in number inputs from UI-libraries, and then adding to these custom arrow buttons whenever handler you like. There is no such event that would be only triggered by clicking native arrow buttons.

CodePudding user response:

you should move inputProps inside InputProps. else you will have eslint warning, no duplicate props allowed. You can use onInput event handler inside inputProps as shown in below code.

ref: https://www.w3schools.com/jsref/event_oninput.asp

<TextField
  name={name}
  type="number"
  placeholder={placeholder}
  label={label}
  InputProps={{
     endAdornment: <InputAdornment position="end">lbs</InputAdornment>,
     inputProps:{
       step: "5",
       onInput:()=> console.log('input changed'),
       style: {
         fontSize: "2em",
         padding: "10px",
         textAlign: "right"
       }
     }
   }}
   value={weight}
   onChange={handleChange}
   onBlur={handleBlur}
   // onStepChange={handleStepChange}
   fullWidth
 />
  • Related