Skip to content Skip to sidebar Skip to footer

Use A Single Handler For Multiple Inputs Onchange Events

I have bunch of inputs and I do not want to have multiple handlers like handleInput1(){},handleInput2(){} and so on. But I have difficulties producing below array of object [{ na

Solution 1:

You can try to do it the follwoing way by distinguishing the different inputs by the name attribute and storing the result in the state

classHelloWorldComponentextendsReact.Component {
  constructor(){
    super();
    this.state = {
      result: []
    }
  }
  handleInput(e) {
      console.log(e.target.value);
      var result = [...this.state.result];
      var idx = result.map(function(val){ return val.name}).indexOf(e.target.name);
      if(idx > -1) {
          result[idx].value=e.target.value;
      } else {
        result.push({name: e.target.name, value:e.target.value});
      }
       this.setState({result})
  }

  handleClick() {
    console.log(this.state.result);
  }

  render() {
    return (      
      <div><div><inputtype="number"name="4"onChange={this.handleInput.bind(this)}/></div><div><inputtype="number"name="3"onChange={this.handleInput.bind(this)}/></div><div><inputtype="number"name="5"onChange={this.handleInput.bind(this)}/></div><buttononClick={this.handleClick.bind(this)}>submit</button></div>
    );
  }
}

React.render(
  <HelloWorldComponentname="Joe Schmoe"/>,
  document.getElementById('react_example')
);

JSBIN

Solution 2:

So you can be explicit and bind the key string onto a single handler function like so:

_handleInput(key, val) {
  let { ..state } = this.state;
  state[key] = val;
  this.setState(state);
}
render() {
  return <div>
           <input
            onChange={this.handleInput.bind(null, key1)}
            value={this.state.key1} />
           <input
            onChange={this.handleInput.bind(null, key2)}
            value={this.state.key2} />
         </div>
}

Solution 3:

Since it's an an array you want to modify you can use array indices. Suppose the initial state is this.

this.state= {
  array: [{
    name:3,
    value:1000
  },{
    name:5,
    value:1000
  }]
}

Then the inputs can be like this (for the one with name 3 which has index 0)

<input value={this.state.array[0].value} onChange={this.handleChange.bind(this,0)}/>

So the value it will display is for the 1st element in the array (with index 0) and the handleChange binds to the event as well as pass the index 0.

handleChange(index,event){
this.setState((prevState) => ({array:[  
        ...prevState.array.slice(0, index),
        Object.assign({},prevState.array[index],{value:event.target.value}),
        ...prevState.array.slice(index + 1)
        ]}))
}

Ok so this might seem a little complicate but let me try to explain here. So the handleChange method takes two parameters - the event corresponding to the input text and the index which is the array index of the element in the state array (0 in our example). So in this.setState we have taken the prevState and used a bit of splicing. ...prevState.array.slice(0,index) corresponds to all elements of the array before the one we are modifying. ...prevState.slice(index+1) corresponds to all those after. So we take these two sets and join them with the modified element in between. The Object.assign() corresponds to the modified element. What it is doing is taking the prevState.array[index] which is the element we are modifying and setting it's value to event.target.value corresponding to the text.

Solution 4:

If you change your state model to have a key per form element and use some nice-to-haves like arrow functions to capture variable scope in a cleaner syntax, you can simplify things:

classHelloWorldComponentextendsReact.Component {

  constructor(props) {
    super(props);
    this.state = {
      "3": {},
      "4": {},
      "5": {}
    }
  }

  handleInput(name, value) {
    this.setState({
      [name]: {
        name: name,
        value: value
      }
    });
  }

  handleClick() {
    console.log(this.state); 
  }

  render() {
    return (      
      <div><div><inputtype="number"value={this.state["3"].value} onChange={(e) => this.handleInput(3, e.target.value)}/></div><div><inputtype="number"value={this.state["4"].value} onChange={(e) => this.handleInput(4, e.target.value)}/></div><div><inputtype="number"value={this.state["5"].value} onChange={(e) => this.handleInput(5, e.target.value)}/></div><buttononClick={(e) => this.handleClick()}>submit</button></div>
    );
  }
}

React.render(
  <HelloWorldComponentname="Joe Schmoe"/>,
  document.getElementById('react_example')
);

Having your state be an array of values not keyed by anything will force you to search through the state and replace it (as some of the other answers have shown).

It's usually a better idea to simplify things to improve readability and comprehension

Recall that React state is additive, so calling setState with just a partial state change will merge it with the existing state. You will only get this benefit if you're keying your data in the state.

Solution 5:

you can add name property to input, and get target.name like this:

_handleInput(event) {
    let name = event.target.name;
    letvalue = event.target.value;
  this.setState({[name] : value});
}

<input
    onChange={this._handleInput}
    value={this.state.key1} 
    name="key1"
/>

Post a Comment for "Use A Single Handler For Multiple Inputs Onchange Events"