10

In my React app (version 15.4.2), I am updating the value of a text input field with JavaScript - however, I have an onChange event listener associated with the input field, and changing the value of the input field does not trigger the handler (good old fashioned typing in the input field does, of course), though the content of the field is correctly updated.

constructor(props) {
    super(props);
    this.onChange = this.onChange.bind(this);
}

onChange(event){
    let attribute = event.target.name;
    let updatedGroup = this.state.group;
    updatedGroup[attribute] = event.target.value;
    this.setState({group: updatedGroup});
}

addMember(memberId) {
    let inputField = document.getElementById("members");
    let inputValues = inputField.value.split(",");
    inputField.value = [...inputValues, memberId];
}

render(){
    <input type="text" id="members" name="members" value={this.state.group.members} onChange={this.onChange} />
}

So when addMember() is called (via button click in a child component), then content of the input field itself is correctly updated, but onChange is not called and thus the state is not updated, etc...

Is there a way that I can programatically set the value of the input field and trigger onChange?

3
  • 1
    Can you provide some more context on what you're trying to do and why? Is addMember() a public method that you're exposing? Why do you need to to do it with a method as opposed to simply passing in props? With React, you should resist the urge to manipulate the DOM directly, the way you're doing. Ie: there's no need to use document.getElementById here. Commented Feb 17, 2017 at 3:51
  • Well I'm pretty new to React, so it's likely that I'm not doing things in the optimal manner. Basically, the text input is a string (from an array) of user ID's - "2,46,3", etc. addMember is triggered when the app user clicks a user's name from a list, and it adds their ID to the input list so that the state (and ultimately, the database) will be updated to reflect this new user. Commented Feb 17, 2017 at 3:59
  • But I dig what you're saying - you've given me some food for thought. Commented Feb 17, 2017 at 4:03

2 Answers 2

2

What I always do in this situation is have your onChange event handler be a function that passes the event data (the character that was entered or the aggregate string) into another function. I put all of the business logic in that function. That way, if I want to invoke the business logic, I just call that method.

Since you are asking "Is there a way that I can programatically set the value of the input field and trigger onChange?" Why not skip onChange and call the business logic function from your function that is programmatically setting the value?

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

4 Comments

Yeah I dig what you're saying - it's getting a little late at night for me, but I'm going to try this approach first thing in the morning - thanks!
This is a pattern I highly recommend. Separate your business logic completely from you view logic. Also, use TypeScript. It's like JavaScript but BETTER! And it compiles down to JavaScript.
Thanks so much for your thoughts - I'm new to React so I'm getting used to thinking like this, very helpful.
This pattern is good in a lot of scenarios outside of React. Also, have you looked into React + Redux?
1

Onchange method will get triggered only when you type something, if you use document.getElementById and replace its values, it will directly replace the value in DOM, onChange will not get triggered in that case. Since you are using the react, I think you should avoid the direct DOM manipulation.

You are using controlled input, so in addMember method instead of updating the value in DOM, update the state value.

Try this addmember method:

addMember(memberId) {
    //let inputField = document.getElementById("members");
    //let inputValues = inputField.value.split(",");
    //inputField.value = [...inputValues, memberId];

    let group = this.state.group.slice();
    group[members] = group[members] + ',' + memberId;
    this.setState({
        group
    });
}

4 Comments

Sorry, I should've specified - that is set in the constructor - I'll edit my question to reflect that.
did you put the console in onchange method, is it not printing the console values ??
Yes, I tried putting a console.log("test") inside the onChange method, it only logs if I type in the text field, but not if the value is changed from calling addMember().
Thank you! I'm new to React, this was very helpful.

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.