Search code examples
javascriptreactjsmobx-react-form

Not changing values of form reactjs


I have a form in which I am generating form fields dynamically . Now Issue is fields which are not dynamically generated are getting input and those field which are dynamically generated are not taking input in fields. name='name' and name='age' fields are not getting input I cant insert data in them . while first two fields owner and description are working fine

import React from "react";
class Form extends React.Component {

  state = {
    cats: [{ name: "", age: "" }],
    owner: "",
    description: ""
  };
  handleChange = e => {
    alert('inot');
    if (["name", "age"].includes(e.target.className)) {
      let cats = [...this.state.cats];
      cats[e.target.dataset.id][
        e.target.className
      ] = e.target.value.toUpperCase();
      this.setState({ cats }, () => console.log(this.state.cats));
    } else {
      this.setState({ [e.target.name]: e.target.value.toUpperCase() });
    }
  };
  addCat = e => {
    this.setState(prevState => ({
      cats: [...prevState.cats, { name: "", age: "" }]
    }));
  };
  handleSubmit = e => {
    e.preventDefault();
  };
  handleClick = e => document.getElementById(e.target.id).remove();

  // changeOption =(e) => {
  //   this.setState.cats(e.target.value);
  // }


  render() {
    let { owner, description, cats } = this.state;
    return (
      <form onSubmit={this.handleSubmit} onChange={this.handleChange}>
        <div className='row mt-5'>
          <div className='col-md-12 mb-5'>
            <h3 className='text-center text-primary'>Create Products Option</h3>
          </div>
          <div className='col-md-3'></div>
          <div className='col-md-3'>
            <label htmlFor='name'>
              <b>Owner</b>
            </label>
            <input
              type='text'
              className='form-control'
              name='owner'
              id='owner'
              value={owner}
            />
          </div>
          <div className='col-md-3'>
            <label htmlFor='description'>
              <b>Description</b>
            </label>
            <input
              type='text'
              className='form-control'
              name='description'
              id='description'
              value={description}
            />
            <button
              className='btn btn-success rounded-0 w-25 float-right mt-2 shadow-none'
              onClick={this.addCat}
            >
              +
            </button>
          </div>
          <div className='col-md-3'></div>
        </div>

        {cats.map((val, idx) => {
          let catId = `cat-${idx}`,
            ageId = `age-${idx}`;
          return (
            <form onSubmit={this.handleSubmit} onChange={this.handleChange}>
            <div id={ageId} key={idx}>
              <div className='row mt-5'>
                <div className='col-md-3'></div>
                <div className='col-md-3'>
                  <label htmlFor={catId}>
                    <b>{`Cat #${idx + 1}`}</b>
                  </label>
                  <input
                    type='text'
                    name='name'
                    data-id={idx}
                    id={catId}
                    value={cats[idx].name}
                    className='name form-control'
                  />


                </div>
                <div className='col-md-3'>
                  <label htmlFor={ageId}>
                    <b>Age</b>
                  </label>
                  <input
                    type='text'
                    name='age'
                    data-id={idx}
                    id={ageId}
                    value={cats[idx].age}
                    className='age form-control'
                  />
                  <button
                    className='btn btn-success rounded-0 w-25 float-right mt-2 shadow-none'
                    onClick={this.addCat}
                  >
                    +
                  </button>
                  <input
                    type='button'
                    name={ageId}
                    data-id={idx}
                    id={ageId}
                    value={"-"}
                    className='age float-right mt-2 mr-3 btn btn-danger w-25 rounded-0 w-25 shadow-none'
                    onClick={this.handleClick}
                  />

                </div>
                <div className='col-md-3'></div>
              </div>

            </div>
            </form>
          );
        })}
        <div className='row mt-3'>
          <div className='col-md-3'></div>
          <div className='col-md-3'>
            <label htmlFor='name'>
              <b>Min Selection</b>
            </label>
            <input
              type='text'
              className='form-control'
              name='min'
              id='min'
              value={""}
            />
          </div>
          <div className='col-md-3'>
            <label htmlFor='description'>
              <b>Max Selection</b>
            </label>
            <input
              type='text'
              className='form-control'
              name='max'
              id='max'
              value={""}
            />
            <input
              className='float-right btn btn-success mt-3'
              type='submit'
              value='Submit'
            />
            {/* <button className="float-right" onClick={this.addCat}>Add new cat</button> */}
          </div>
          <div className='col-md-3'></div>
        </div>
      </form>
    );
  }
}
export default Form;

Solution

  • Codesandbox here. Looks like you should be seeing some errors in your console that might provide some explanation:

    Warning: Failed prop type: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`.
    

    Detailed answer

    Working Sandbox here. There are a few things wrong here:

    Your handleChange function needs to change

    Your function is looking at className which won't work. Your inputs return form-control name for example. Instead try using the element's name.

    Updated function:

      handleChange = e => {
        if (["name", "age"].includes(e.target.name)) {
          let cats = [...this.state.cats];
          cats[e.target.dataset.id][e.target.name] = e.target.value.toUpperCase();
          this.setState({ cats }, () => console.log(this.state.cats));
        } else {
          this.setState({ [e.target.name]: e.target.value.toUpperCase() });
        }
      };
    

    Aside

    Do not render <form> elements in other <form> elements. Don't do this. You don't need another form here. Just remove that.

    // Line 76-80:
            {cats.map((val, idx) => {
              let catId = `cat-${idx}`,
                ageId = `age-${idx}`;
              return (
                <form onSubmit={this.handleSubmit} onChange={this.handleChange}>
    // ...