How to Clear Input Values of Dynamic Form in React

freeCodeCampfreeCodeCamp
3 min read

There's a lot to consider when working on a React application, especially when they involve forms. Even if you're able to create a submit button and update your app's state the way you want, clearing the forms can be difficult.

Say your application has dynamic forms like this:

import React from "react";
import ReactDOM from "react-dom";
import Cart from "./Cart";

import "./styles.css";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      Items: [
        {
          name: "item1",
          description: "item1",
          group: "groupA",
          dtype: "str"
        },
        {
          name: "item2",
          description: "item2",
          group: "groupA",
          dtype: "str"
        },
        {
          name: "item3",
          description: "item3",
          group: "groupB",
          dtype: "str"
        },
        {
          name: "item4",
          description: "item4",
          group: "groupB",
          dtype: "str"
        }
      ],
      itemvalues: [{}]
    };
    this.onChangeText = this.onChangeText.bind(this);
    this.handleReset = this.handleReset.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.findFieldIndex = this.findFieldIndex.bind(this);
    this.trimText = this.trimText.bind(this);
  }

  onChangeText = e => {
    const valuesCopy = [...this.state.itemvalues];
    //debugger;

    // get data-group value
    const itemvalue = e.target.dataset.group;

    if (!valuesCopy[0][itemvalue]) {
      valuesCopy[0][itemvalue] = [];
    }

    const itemvalues = valuesCopy[0][itemvalue];
    const index = this.findFieldIndex(itemvalues, e.target.name);

    if (index < 0) {
      valuesCopy[0][itemvalue] = [
        ...itemvalues,
        { [e.target.name]: e.target.value.split(",").map(this.trimText) }
      ];
    } else {
      // update the value
      valuesCopy[0][itemvalue][index][e.target.name] = e.target.value
        .split(",")
        .map(this.trimText);
    }

    // console.log(itemsCopy);

    this.setState({ itemvalues: valuesCopy });
  };
  findFieldIndex = (array, name) => {
    return array.findIndex(item => item[name] !== undefined);
  };
  trimText(str) {
    return str.trim();
  }

  handleReset = () => {
    this.setState({
      itemvalues: [{}]
    });
  };

  handleSubmit = () => {
    console.log(this.state.itemvalues);
  };

  render() {
    return (
      <Cart
        Items={this.state.Items}
        handleSubmit={this.handleSubmit}
        handleReset={this.handleReset}
        onChangeText={this.onChangeText}
      />
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
import React from "react";
import Form from "./Form";

const Cart = props => {
  return (
    <div>
      <Form Items={props.Items} onChangeText={props.onChangeText} />

      <button onClick={props.handleSubmit}>Submit</button>
      <button onClick={props.handleReset}>Reset</button>
    </div>
  );
};

export default Cart;
import React from "react";

const Form = props => {
  return (
    <div>
      {props.Items.map((item, index) => (
        <input
          name={item.name}
          placeholder={item.description}
          data-type={item.dtype}
          data-group={item.group}
          onChange={e => props.onChangeText(e)}
          key={index}
        />
      ))}
    </div>
  );
};
export default Form;

And simple input boxes are rendered to the page:

Image

When a user enters text into one of the input boxes, it's saved to the application state in groups like this:

Itemvalues:
  0:
    groupA: 
            item1: itemvalue1
            item2: itemvalue2
    groupB: 
            item3: itemvalue3
            item4: itemvalue4

It's pretty complicated, but you managed to get that working.

In handleReset, you're able to set itemvalues back to a null state when the "Reset" button is pressed:

handleReset = () => {
  this.setState({
    itemvalues: [{}]
  });
};

But the problem is that the text is not cleared from all of the input boxes:

Image

You've already handled storing the actual text in the state, so here's a simple way to clear the text from all input boxes.

How to clear the values all inputs

At the top of handleReset, use document.querySelectorAll('input') to select all the input elements on the page:

handleReset = () => {
  document.querySelectorAll('input');
  this.setState({
    itemvalues: [{}]
  });
};

document.querySelectorAll('input') returns a NodeList, which is a bit different than an array, so you can't use any useful array methods on it.

To turn it into an array, pass document.querySelectorAll('input') to Array.from():

handleReset = () => {
  Array.from(document.querySelectorAll('input'));
  this.setState({
    itemvalues: [{}]
  });
};

Now all you have to do is iterate through each of the inputs and set its value attribute to an empty string. The forEach method is a good candidate for this:

handleReset = () => {
  Array.from(document.querySelectorAll("input")).forEach(
    input => (input.value = "")
  );
  this.setState({
    itemvalues: [{}]
  });
};

Now when a user presses the "Reset" button, the value of every input is cleared, too:

Image

0
Subscribe to my newsletter

Read articles from freeCodeCamp directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

freeCodeCamp
freeCodeCamp

Learn to code. Build projects. Earn certifications—All for free.