LAJ
LAJ

Reputation: 29

Creating a generalised onChange() function for different inputs without the use of name tag

I'm trying to create a generalized handleChange() function for all my input fields. I have over 30 input fields, so there is not really an option to have one handleChange method for each input, as this would create tons of boilerplate code. In the example below I have tried to create a function that will handle any input.

For my project, I'm using Ant design, which does not seem to support the name attribute inside their form elements (e.g. InputNumber/Input, etc.)

Example of an InputNumber field:

<InputNumber name='myNumber' min={1} max={100000} placeholder='Enter number'  value={this.state.myNumber} onChange={handleChange}/>

This is my attempt at writing a generalized onChange method. But it passes this error: Cannot read property 'name' of undefined

 handleChange = (e) => {
    this.setState({
      [e.target.name]: e.target.value
    });

This method would allow me to reach any selected input element and update that specific one. However, this does work due to the lack of a name attribute.

As suggested below, this approach works, but still leaves me without a generalized solution - a way to handle any input and map to the correct state value.

state = {
    myNumber: 0,
    myNumber2: 0,
    myNumber3: 0
  };

  handleChange = e => {
    this.setState({
      myNumber: e
    });
  };

In the example below the handleChange function will only update myNumber, not myNumber2 and myNumber3.

<InputNumber name='myNumber' min={1} max={100000} placeholder='Enter number'  value={this.state.myNumber} onChange={handleChange}/>
<InputNumber name='myNumber2' min={1} max={100000} placeholder='Enter number'  value={this.state.myNumber2} onChange={handleChange}/>
<InputNumber name='myNumber3' min={1} max={100000} placeholder='Enter number'  value={this.state.myNumber3} onChange={handleChange}/>

Any suggestions to a workaround?

Upvotes: 1

Views: 262

Answers (2)

Dennis Vash
Dennis Vash

Reputation: 53964

According to InputNumber API, onChange accepts a Number|String, e.target.value will always resolve run time error.

onChange: The callback triggered when the value is changed - function(value: number | string)

Here is an example, where I suppose in writing:

<InputNumber name='myNumber' min={1} max={100000} placeholder='Enter number'  value={this.state.myNumber} onChange={handleChange}/>

You meant using a class component, because onChange={handleChange} as you described must be a part of a class.

export default class App extends React.Component {
  state = {
    myNumber: 0
  };

  handleChange = e => {
    this.setState({
      myNumber: e
    });
  };

  render() {
    return (
      <FlexBox>
        <InputNumber
          name="myNumber"
          min={1}
          max={100000}
          placeholder="Enter number"
          value={this.state.myNumber}
          onChange={this.handleChange}
        />
      </FlexBox>
    );
  }
}

Edit Q-56934468-InputNumber


  • If you want to use a generic method handleChange you should change the component type from InputNumber to Input, that's because you want to access name="myNumber" property.
handleChange = e => {
  e.persist();
  this.setState({
    [e.target.name]: e.target.value
  });
};
  • A better approach keeps using InputNumber and implement handleChange as curried function:
handleChange = name => e => {
  this.setState({
    [name]: e
  });
};

Check the example of both approaches:

class AppInputNumber extends React.Component {
  state = {
    myNumber: 0,
    myNumber2: 0,
    myNumber3: 0
  };

  handleChange = name => e => {
    this.setState({
      [name]: e
    });
  };

  render() {
    return (
      <FlexBox>
        <InputNumber
          min={1}
          max={100000}
          placeholder="Enter number"
          value={this.state.myNumber}
          onChange={this.handleChange('myNumber')}
        />
        <InputNumber
          min={1}
          max={100000}
          placeholder="Enter number"
          value={this.state.myNumber2}
          onChange={this.handleChange('myNumber2')}
        />
        <InputNumber
          min={1}
          max={100000}
          placeholder="Enter number"
          value={this.state.myNumber3}
          onChange={this.handleChange('myNumber3')}
        />
      </FlexBox>
    );
  }
}

export default class App extends React.Component {
  state = {
    myNumber: 0,
    myNumber2: 0,
    myNumber3: 0
  };

  handleChange = e => {
    e.persist();
    this.setState({
      [e.target.name]: e.target.value
    });
  };

  render() {
    return (
      <FlexBox>
        <Input
          name="myNumber"
          min={1}
          max={100000}
          type="number"
          placeholder="Enter number"
          value={this.state.myNumber}
          onChange={this.handleChange}
        />
        <Input
          name="myNumber2"
          min={1}
          max={100000}
          type="number"
          placeholder="Enter number"
          value={this.state.myNumber2}
          onChange={this.handleChange}
        />
        <Input
          name="myNumber3"
          min={1}
          max={100000}
          type="number"
          placeholder="Enter number"
          value={this.state.myNumber3}
          onChange={this.handleChange}
        />
        <AppInputNumber />
      </FlexBox>
    );
  }
}

Edit Q-56934468-GenericHandle


Upvotes: 0

AlexMin314
AlexMin314

Reputation: 22

I am not sure but if the e is an event object, try this

e.target.getAttribute('name')

Upvotes: -1

Related Questions