0

I'm trying to make a dynamic input form, which by clicking the button will generate a new row of description input field. I use an array inside the state to keep track of them:

state = {
descriptions: [
        {
        elementType: 'input',
        elementConfig: {
            type: 'text',
            placeholder: 'Description'
        },
        value: '',
        validation: {
            required: true
        },
        valid: false,
        touched: false     
    }]
}

So in my render method, I use a variable like this to populate my form:

let descriptionsForm = (
        <form>
        {this.state.descriptions.map((description, index) => (
            <Input
                key={index}
                elementType={description.elementType}
                elemenyConfig={description.elementConfig}
                value={description.value}
                invalid={!description.valid}
                shouldValidate={description.validation}
                touched={description.touched}
                changed={(event) => this.descriptionInputChangedHandler(event, index)}
                />
        ))}
        </form>
        <Button btnType={"Success"} clicked={this.pushDescription}>Add Description</Button>

    )

This is the pushDescription function:

pushDescription = () => {
    var d = {
        elementType: 'input',
        elementConfig: {
            type: 'text',
            placeholder: 'Description'
        },
        value: '',
        validation: {
            required: true,
            isEmail: true
        },
        valid: false,
        touched: false     
    };

    this.state.descriptions.push(d);
    console.log(this.state.descriptions);
}

So when I clicked on the "Add Description" button, the console flashes 1 second of the updated descriptions which have 2 elements in it, but soon refreshes to the original state. The website does not change at all.

What am I doing wrong? Any help appreciated.


EDIT: After fixing the form tag problem.Seems like when I type something into the input forms, the newly created forms does show up. Why are they not updating when I click on the button right away?


Thanks for all you guys answering, the working update handler looks like this:

pushDescription = () => {


    var d = {
        elementType: 'input',
        elementConfig: {
            type: 'text',
            placeholder: 'Description'
        },
        value: '',
        validation: {
            required: true,
            isEmail: true
        },
        valid: false,
        touched: false     
    };

    let newDescriptions = [
        ...this.state.descriptions,
        d
    ]


    // this.state.descriptions.push(d);
    this.setState({ descriptions: newDescriptions})
    console.log(this.state.descriptions);
}
Kei
  • 611
  • 2
  • 11
  • 24

3 Answers3

2

it seems like your component is not re-rendering. try

this.setState({ description: this.state.description.push(d) });

this will get your component to re-render as a component re-renders in only following cases:

  1. this.setState method is called
  2. this.forceUpdate() method is called
  3. Or changes in the props being supplied to the component.
Pranay Tripathi
  • 1,614
  • 1
  • 16
  • 24
1

If you remove <form> element it would work.

Probably Button in <form> element acts like a submit button and refreshes your page.

See this answer to a similar question.

trkaplan
  • 3,217
  • 2
  • 23
  • 26
  • 1
    Thanks! That did work. But then while the state seems to be updating, the displayed input row still hasn't increase, could you tell me how I should fix that? – Kei Oct 07 '18 at 22:40
  • Can you reproduce the problem on a jsfiddle/ codepen? – trkaplan Oct 07 '18 at 22:47
  • I took sometime to try doing that, but the other components are heavily relying on others so didn't really work out. Sorry about that. Here is a gist of the container if that helps: https://gist.github.com/kyujyokei/37c2e56e0b7a87f7a32cac8d7e230052 – Kei Oct 07 '18 at 23:07
0

try updating your render method

let descriptionsForm = (
    <form>
    {this.state.descriptions.map((description, index) => (
        <Input
            key={index}
            elementType={description.elementType}
            elemenyConfig={description.elementConfig}
            value={description.value}
            invalid={!description.valid}
            shouldValidate={description.validation}
            touched={description.touched}
            onChange={(event) => this.descriptionInputChangedHandler(event, index)}
            />
    ))}
    <Button btnType={"Success"} onClick={this.pushDescription}>Add Description</Button>
    </form>
)

use 'onClick' rather then 'clicked', and 'onChange' rather than 'changed'

hope it helps :)

Ewomazino Ukah
  • 2,286
  • 4
  • 24
  • 40
  • Thanks for replying, but I tried that and nothing worked. The and are components which I pass clicked and changed as props into their onClick and onChange field. So I guess that wasn't the problem... – Kei Oct 07 '18 at 22:29
  • @Kei can you create a fiddle? more like reproduce the problem on jsfiddle/codepen, so its easier to help – Ewomazino Ukah Oct 07 '18 at 22:31
  • I tried that but didn't work well since it's relying on a lot of libraries and other components. But here's a gist of this component if that helps: https://gist.github.com/kyujyokei/37c2e56e0b7a87f7a32cac8d7e230052 – Kei Oct 07 '18 at 23:12