1

Good day,

I'm new with react.js I'm trying to create a basic data binding using onChange of the input. The problem is, I'm assigning to object with it's properties. Not directly to the property.

Now I'm receiving the error Warning: A component is changing a controlled input of type text to be uncontrolled. when I type-in a character in my inputs.

Here's my code:

interface IProps { }

interface IFloorInfo {
    id: number
    name: string,
    type: string,
    condition: string
}

interface IFloorInfoState {
    floor: IFloorInfo
}

export default class Floors extends React.Component<IProps, IFloorInfoState> {
    state: IFloorInfoState
    constructor(props: any){
        super(props)

        this.state = {
            floor: {
                id: 0,
                name: '',
                type: '',
                condition: ''
            }
        }
    }

    ...

    render() {
        return (
            <div>
                <input type="text" value={this.state.floor.name} onChange={(e)=>this.inputChanges(e)} />
                <input type="text" value={this.state.floor.type} onChange={(e)=>this.inputChanges(e)} />
                <input type="text" value={this.state.floor.condition} onChange={(e)=>this.inputChanges(e)} />
            </div>
        )
    }

}

Now this is my inputChanges method that detects if there's a changes in the input

inputChanges = (e:any) => {
    this.setState({ floor: e.target.value });
}

Thank you in advance.

2

2 Answers 2

1

The problem is with your following code. According to this code, your state will be {floor: "input value"}

inputChanges = (e:any) => {
    this.setState({ floor: e.target.value });
}

But what you actually want is

inputChanges = (e:any) => {
    // copying all values of floor from current state;
    var currentFloorState = {...this.state.floor};

    // setting the current input value from user
    var name = e.target.name;
    currentFloorState[name] = e.target.value;

    this.setState({ floor: currentFloorState });
}


As for multiple properties: You can add name property to your element and use it in your changeHandler

render() {
   return (
     <div>
       <input type="text" value={this.state.floor.name} name="floor" onChange={(e)=>this.inputChanges(e)} />
    <input type="text" value={this.state.floor.type} name="type" onChange={(e)=>this.inputChanges(e)} />
     </div>
        )
    }

For demo, you can refer this https://codesandbox.io/s/jolly-ritchie-e1z52

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

3 Comments

what if I have another properties? like type other than name?
I updated the question, I added different properties like type and condtion
I tried to this for the other properties, currentFloorState.name = e.target.value; but the properties have the same value from the first inputs
0

In this code, you don't specify which property that you want to bind.

inputChanges = (e:any) => {
    this.setState({ floor: e.target.value });
}

What you can do, is something like this.

inputChanges = (e:any) => {
    this.setState({
        ...this.state,
        floor: { ... this.state.floor, [e.currentTarget.name]: e.currentTarget.value}
    })
}

Basically, you're binding whatever property that matches inside your this.state.floor object.

1 Comment

There are two problems with this answer: 1. setState performs a shallow merge of the current state with the new state so ...this.state doesn't need to be there. 2. If the new state depends on the old state, ie you lookup this.state in the new state, you should pass a callback to setState. See reactjs.org/docs/react-component.html#setstate for more info

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.