brslv
brslv

Reputation: 526

Removing inputs leads to incorrect values

Ok, so the problem is pretty simple, but hard to explain.

I'm making an InputGenerator component, which generates a list of inputs.

Each generated input has a corresponding "remove" button next to it. The two elements (the input and the button) are wrapped in a div inside a map function. The div has a unique key prop. It looks like this (this is the whole component's jsx):

        <div style={[InputGenerator.style.wrapper]}>
            <div className="container" style={InputGenerator.style.container}>
                {this.state.inputs.map((input, idx) => {
                    return (
                        <div key={idx} style={[
                            InputGenerator.style.row,
                            InputGenerator.count > 1 && idx > 0 ? InputGenerator.style.input.pushTop : {},
                        ]}>
                            <InputText
                                id={input.id}
                                name={input.name}
                                placeholder={input.placeholder}
                                style={input.style}
                            />
                            <Button
                                style={InputGenerator.style.remove}
                                type={Button.TYPES.BASIC}
                                icon="ion-close-round"
                                onClick={this.remove.bind(this, input.id)}
                            />
                        </div>
                    );
                })}
            </div>

            <div className="controls" style={InputGenerator.style.controls}>
                <Button icon="ion-plus" type={Button.TYPES.PRIMARY} title="Add ingredient" onClick={this.add.bind(this)}/>
            </div>
        </div>

As you may see, all the inputs are kept in the this.state object and each one is given an unique id.

Here are the are add and remove methods:

add():

add() {
    InputGenerator.count++;

    const newInput = {
        id: this.id,
        name: this.props.name,
        placeholder: this.props.placeholder,
        style: this.style,
        value: '',
    };

    const inputs = this.state.inputs;

    inputs.push(newInput);

    this.setState({ inputs });
}

remove():

remove(id) {
    this.setState({
        inputs: this.state.inputs.filter(i => i.id !== id),
    });
}

The problem is:

So, I'm open for ideas and suggestions how to proceed.

Here's an isolated sandbox to play around with my component and see the "bug" in action: https://codesandbox.io/s/5985AKxRB

Thanks in advance! :)

Upvotes: 0

Views: 112

Answers (1)

Ved
Ved

Reputation: 12103

The issue you facing is because you are not handling state properly. You need to update state when you change input value.

  handleChange(index,event) {
    let inputs = this.state.inputs;
    inputs[index].value = event.target.value;
    this.setState({inputs:inputs})
  }

DEMO : DEMO

Here is the updated code:

import React, { Component } from 'react';
    import { render } from 'react-dom';
    import Hello from './Hello';

    const styles = {
      fontFamily: 'sans-serif',
      textAlign: 'center',
    };

    const App = () =>
      <div style={styles}>
        <InputGenerator />
      </div>;

    class InputGenerator extends Component {
      constructor() {
        super();
        this.state = {
          inputs: [],
        };
      }
      componentWillMount() {
        this.add();
      }
      handleChange(index,event) {
        let inputs = this.state.inputs;
        inputs[index].value = event.target.value;
        this.setState({inputs:inputs})
      }
      add() {
        InputGenerator.count++;

        const newInput = {
          id: this.id,
          name: this.props.name,
          placeholder: this.props.placeholder,
          style: this.style,
          value: '',
        };

        const inputs = this.state.inputs;

        inputs.push(newInput);

        this.setState({ inputs });
      }
      get id() {
        if (this.props.id) {
          return `${this.props.id}-${InputGenerator.count}`;
        }

        return `InputGeneratorItem-${InputGenerator.count}`;
      }
      get style() {
        return [];
      }
      remove(id) {

        var state = this.state;
        state.inputs = state.inputs.filter(i => i.id !== id);
        this.setState({
          inputs: state.inputs
        });
      }
      render() {
        return (
          <div>
            <div className="container">
              {this.state.inputs.map((input, idx) => {
                return (
                  <div key={idx}>
                    <input
                      id={input.id}
                      name={input.name}
                      value = {input.value}
                      onChange={this.handleChange.bind(this,idx)}
                      placeholder={input.placeholder}
                    />
                    <button onClick={this.remove.bind(this, input.id)}>
                      Remove
                    </button>
                  </div>
                );
              })}
            </div>

            <div className="controls">
              <button onClick={this.add.bind(this)}>Add</button>
            </div>
          </div>
        );
      }
    }

    InputGenerator.count = 0;

    render(<App />, document.getElementById('root'));

Upvotes: 2

Related Questions