0

I have a reactjs code adding forms on button click. Now I want to delete an individual form on remove button click in component. I have remove button in Test Component. The problem I am facing when I press any remove button all forms are deleted, I just want to delete a particular form.

App.js

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Test from './Test.js';

class App extends Component {
  state={
    numform: 0
  }

  Addform()
  {
    this.setState({
      numform: this.state.numform + 1
    }); 
  }

  render() {
    const form = [];
    for(var i=0;i<this.state.numform;i+=1)
    {
      form.push(<Test key={i}/>);
    }
    return(
        <div className="App ">
          <div className="App-header App-intro">
            <button onClick={()=>this.Addform()}>+</button>
          </div>
            {form}
        </div>
    );
  }

}

export default App;

Test.js

import React, { Component } from 'react';
import logo from './logo.svg';

class Test extends Component {
  Removeform()
  {
    this.props.delete_this(this.props.key); 
  }
  render() {
    return(
        <form>

          <input type="text" name="i1"></input> 
          <input type="text" name="i2"></input>
          <input type="submit" value="submit"></input>
          <button value="Remove" onClick={()=>this.Removeform()}>Remove</button>
        </form>
    );
  }
}

export default Test;
3
  • First of all you can't use key through props as it is used by react you have to pass another prop with index and use that prop and also you didn't pass delete_this in props and delete_this is also not defined in your app component Commented Aug 5, 2018 at 13:27
  • You don't have actual delete function. It does not delete anything, it just reload the page since you don't use e.preventDefault in your function. What is your intent. You just decrement a form one by one or do you want to delete a specific form here? If this is so, you can't create general forms, you need to use separate ones. Or you can index as @AbhaySehgal suggested but personally I don't like this approach. Commented Aug 5, 2018 at 13:27
  • But, looking your code again this is not possible with indexes either since you are not keeping any form info in your state in anywhere. So, you can decrement the form number by one, but you can't delete a specific form. Commented Aug 5, 2018 at 14:31

2 Answers 2

1

Here is a probably wrong way of doing this. I've changed some names for the functions and state. Also, you need a remove function to pass your Test component and call it with the id (here it is form prop) of your form.

For the forms, I'm creating an array including numbers. After creating each form this number is incremented. Then by mapping this array I'm rendering the forms with a form prop. To remove the form, I'm filtering the array and returning a new one without this number.

Again, for my opinion this is a wrong way of doing this. Just create your forms as objects and give them unique id's.

class App extends React.Component {
  state = {
    forms: [],
    lastNum: 0,
  }

  addForm = () => {
    this.setState( prevState => ( {
      forms: [ ...prevState.forms, prevState.lastNum++ ],
    } ));
  }

  removeForm = form => {
    const newForms = this.state.forms.filter( el => el !== form  );
    this.setState( { forms: newForms } );
  }

  render() {
    const forms = this.state.forms.map( form => (
      <Test key={form} form={form} removeForm={this.removeForm} />
    ));

    return (
      <div className="App ">
        <div className="App-header App-intro">
          <button onClick={this.addForm}>+</button>
        </div>
        {forms}
      </div>
    );
  }
}

const Test = ( props ) => {
  const handleRemove =  e => {
    e.preventDefault();
    props.removeForm( props.form );
  }
  return (
    <form>
      <input type="text" name="i1"></input>
      <input type="text" name="i2"></input>
      <input type="submit" value="submit"></input>
      <button value="Remove" onClick={handleRemove}>Remove</button>
    </form>
  );
}


ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Update

Here is maybe a little bit enhanced one. Using objects for forms, keeping them by ids. But, it's your code, it's your logic. For example in this form there are only two inputs and their names are fixed as in your example. Do you only want two of them or do you want more? Your code, your logic.

class App extends React.Component {
  state = {
    forms: {},
  };

  addForm = () => {
    const newForm = {
      id: guid(),
      i1: "",
      i2: "",
    }
    this.setState(prevState => ({
      forms: { ...prevState.forms, [newForm.id]: newForm },
    }));
  };

  removeForm = id => {
    const forms = { ...this.state.forms };
    delete forms[id];
    this.setState({ forms });
  };

  onChange = ( e ) => {
    const { id, name, value } = e.target;
    this.setState( prevState => ( {
      forms: { ...prevState.forms, [id]: { ...prevState.forms[id], [name]: value } }
    } ));
  };

  onSubmit = id => { 
    const { i1, i2 } = this.state.forms[id];
    alert( `Form id: ${id}, input1: ${i1}, input2: ${i2} ` );
  }

  renderForms = () => Object.keys(this.state.forms).map(key => (
    <FormItem
      key={this.state.forms[key].id}
      id={this.state.forms[key].id}
      removeForm={this.removeForm}
      onChange={this.onChange}
      onSubmit={this.onSubmit}
      />
  ));

  render() {
    return (
      <div className="App ">
        <div className="App-header App-intro">
          <button onClick={this.addForm}>+</button>
        </div>
        {this.renderForms()}
      </div>
    );
  }
}

const FormItem = (props) => {
  const { id, removeForm, onChange, onSubmit } = props;
  
  const handleRemove = () => removeForm(id);
 
  const handleSubmit = e => {
    e.preventDefault();
    onSubmit( id );
  } 

  return (
    <form onSubmit={handleSubmit}>
      <input id={id} onChange={onChange} type="text" name="i1"></input>
      <input id={id} onChange={onChange} type="text" name="i2"></input>
      <button type="submit">Submit</button>
      <button value="Remove" onClick={handleRemove}>Remove</button>
    </form>
  );
}

function guid() {
  function s4() {
    return Math.floor((1 + Math.random()) * 0x10000)
      .toString(16)
      .substring(1);
  }
  return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

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

5 Comments

Thank you, Its Working now :) . By the way, how can we get form inputs value on submit.
You are welcome. For the submit question, this is why I said this is a wrong way of doing this. If you want to create dynamic forms like that you should think a more clever and complex way. For example you need to keep your forms as objects maybe. You need to give them unique id's, unique names and some fields. Then using these names you can use a general handleChange method to update your state.
How can I use them, Please suggest me any reference or example for it. Thank you.
There is not a single way to do this. You can try to write your own code with your own logic. As a learner, I've updated my answer and provided an example. Still, it would not be the best way but it works. Again, there are many ways of doing this and it depends on your needs. ie: stackoverflow.com/questions/51727770/…
Thank you so much, It is perfect now.
0

There are a couple things wrong here based on the code you posted.

First of all, take note that nothing is actually being deleted. Because you are using a form tag, when you press a button things are being submitted. Which basically causes the component to refresh as consequence. To make it not do this, all you have to do as a evt.preventDefault when clicking the button. So in your case, the new code will look something like this:

  Removeform(evt)
  {
    evt.preventDefault()
    // Do delete related stuff
  }

...
// In the render of the same component
  render() {
    return(
        <div>

          <input type="text" name="i1"></input> 
          <input type="text" name="i2"></input>
          <input type="submit" value="submit"></input>
          <button onClick={(evt)=>this.Removeform(evt)}>Remove</button>
        </div>
    );
  }

Secondly, I believe that by design you aren't allowed to use key as props. So regardless of what value you pass in, it will always be undefined. You will have to name your key prop something else. For this example, we will just call it blah to prove that it could be anything, but key.

for(var i=0;i<this.state.numform;i+=1)
{
  form.push(<Test blah={i}/>);
}

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.