0

I'm having a problem in dynamically generating input fields in react. So I have a keys state and I need to have an input field for each key and also I have tried this link: How to implement a dynamic form with controlled components in ReactJS? but the problem is that the my values state is empty so it will render nothing regarding keys and when I did it with this.ModifyList() it shows input fields regarding each key but it does not have onChange mehtod. the onChange method causes the error when using the this.createUI() . Also in the end I would like to submit the values of input fields.

Is there any suggestion on how to solve this problem?

my Code Below:

export class FileUploadComponent extends Component {
    constructor(props) {
        super(props);
        this.state = {
            //Keys: [],
            //values: [],
            modify: { Keys: ['key1' , 'key2' , 'key3'], values: [] }

        }
        this.handleSubmit = this.handleSubmit.bind(this);

    }
    
    createUI() {
        const { modify } = this.state;
        const keys = modify.Keys
        const values = modify.values
        const val = keys.map(function (item, i) {
            values.map(function (el, i) {
                return <div key={i}>
                    <label>{item}</label>
                    <input type="text" onChange={this.handleChange.bind(this, i)} />
                </div>
            })

        });
        return val;
    }
    
    handleChange(event, i) {
        const {modify} = this.state;
        let values = [...modify.values];
        values[i] = event.target.value;
        this.setState({ values: values });

    }
    handleSubmit(event) {
        alert('A name was submitted: ' + this.state.values.join(', '));
        event.preventDefault();
    }

    ModifyList() {
        const { modify } = this.state;
        const keys = modify.Keys
        const val = keys.map(function (item, i) {
            return <div>
                <label>{item}</label>
                <input type="text" />
            </div>

        });
        return val;
    }
        render() {
        return (
            <div>
                <form onSubmit={this.handleSubmit}>
                    {/*this.ModifyList()*/}
                    {this.createUI()}
                    <input type="submit" className="btn btn-primary" value="Search !" />
                     <input type="submit" className="btn btn-primary" value="Edit !" />
                 </form>
             </div>
        )
    }
}

export default FileUploadComponent

8
  • 1
    what is the error you get when onChange called? you can use a better data structure instead of having one array for the keys and another for the values you can use an object have all keys you want and empty value for each property Commented Dec 3, 2020 at 16:50
  • I think your parameters in your handleChange are reversed. I think it should be handleChange(event, i). Commented Dec 3, 2020 at 16:51
  • @AliFaris yes I have changed it to modify: {Keys: [ ] , values :[ ] } but still same error, TypeError: Cannot read property 'handleChange' of undefined in case of this.createUI() Commented Dec 3, 2020 at 17:07
  • Hi, you can initialize value as Array.of(Keys.length) Commented Dec 3, 2020 at 17:13
  • 1
    Please update your code to see what is causing this. Commented Dec 3, 2020 at 17:58

1 Answer 1

0

You have some some scope issue. One of the main difference between a fat-arrow function and a function declared with the function keyword is that the latter has its own scope, meaning that if you call this inside of it, you are referencing its scope.

In your createUI function, switch your functions to fat-arrow functions and you are all set. Just remember to bind your handle change function in your constructor.

export class FileUploadComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      //Keys: [],
      //values: [],
      modify: { Keys: ["key1", "key2", "key3"], values: [""] }
    };

    this.handleSubmit = this.handleSubmit.bind(this);
    this.handleChange = this.handleChange.bind(this);
  }

  createUI() {
    const { modify } = this.state;
    const keys = modify.Keys;
    const values = modify.values;
    
    const val = keys.map((item, i) => {
      return values.map((el, i) => {
        return (
          <div key={i}>
            <label>{item}</label>
            <input
              type="text"
              onChange={(event) => this.handleChange(event, i)}
            />
          </div>
        );
      });
    });
    return val;
  }

  handleChange(event, i) {
    const { modify } = this.state;
    let values = [...modify.values];
    values[i] = event.target.value;
    this.setState({ values: values });
  }

  handleSubmit(event) {
    alert("A name was submitted: " + this.state.values.join(", "));
    event.preventDefault();
  }

  ModifyList() {
    const { modify } = this.state;
    const keys = modify.Keys;
    const val = keys.map(function (item, i) {
      return (
        <div>
          <label>{item}</label>
          <input type="text" />
        </div>
      );
    });
    return val;
  }

  render() {
    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          {/*this.ModifyList()*/}
          {this.createUI()}
          <input type="submit" className="btn btn-primary" value="Search !" />
          <input type="submit" className="btn btn-primary" value="Edit !" />
        </form>
      </div>
    );
  }
}

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.