1

just a bit of background, I am really new to javascript and web development but have been having fun doing some tutorials on React. Also my first time posting on stackoverflow!

I am building a component to show a list of yes/no questions and users have to respond by selecting radio buttons and optionally adding some comments in a textarea. I'm not really sure how I am supposed to set the state for an array of inputs generated using map.

I have an array holding my questions:

var questions = [
    {id:"1", text:"Is the source up to date?"},
    {id:"2", text:"Question 2 placeholder"},
    {id:"3", text:"Question 3 placeholder"},
]

and here is my (unfinished) component:

var QuestionList = React.createClass({
    getInitialState: function () {
        return {
            commentText: "",
        }
    },

    onUpdateComments: function (e) {
        this.setState({
            commentText: e.target.value
        });
    },
    render: function () {
        var QuestionLines = this.props.questions.map(function(question) {
            return (
                <div key={question.id}>
                    <div>
                        <div>
                            {question.text}
                        </div>
                        <label>
                            <input type="radio" name={question.id} value = {question.id+'Y'}/>Yes
                        </label>
                        <label>
                            <input type="radio" name={question.id} value = {question.id+'N'}/>No
                        </label>
                    </div>
                    <div>
                        <textarea 
                            name = {question.id}
                            onChange = {this.onUpdateComments}
                            placeholder="Enter comments here" 
                            value={this.state.commentText} />
                    </div>
                </div>
            );
        }, this);
        return (
            <div>
                {QuestionLines}
            </div>
        )
    }
});

The app right now displays the same text in all 3 textareas, and I can see that this is because I am storing all changes to textarea in the same commmentText state. However, I am really stumped as to what I need to do to separate these and make this work. Any help would be appreciate.

Also, as I mentioned I am super new to this so if anything is off about how I am structuring my component, please let me know.

Thanks!

3 Answers 3

1

I would do something like that:

var QuestionList = React.createClass({
    getInitialState: function () {
        return { comments: {} } //set internal state comment as an empty object
    },

    onUpdateComments: function (id, e) {

        /*
            you can modify your state only using setState. But be carefull when trying to grab actual state and modify it's reference.
            So, the best way is to create a new object (immutable pattern), and one way of doing that is to use Object.assign
        */
        var comments = Object.assign({}, this.state.comments);

        /* set, for instance, comment[1] to "some text" */
        comments[id] = e.target.value;

        /* set the state to the new variable */
        this.setState({comments: comments});


    },
    render: function () {
        var QuestionLines = this.props.questions.map(function(question) {

            /* grab the comment for this ID. If undefined, set to empty */
            var comment = this.state.comments[question.id] || "";

            return (
                <div key={question.id}>
                    <div>
                        <div>
                            {question.text}
                        </div>
                        <label>
                            <input type="radio" name={question.id} value = {question.id+'Y'}/>Yes
                        </label>
                        <label>
                            <input type="radio" name={question.id} value = {question.id+'N'}/>No
                        </label>
                    </div>
                    <div>
                        <textarea 
                            name = {question.id}
                            onChange = {this.onUpdateComments.bind(this,question.id)}
                            placeholder="Enter comments here" 
                            value={comment} />
                    </div>
                </div>
            );
        }, this);
        return (
            <div>
                {QuestionLines}
            </div>
        )
    }
});
Sign up to request clarification or add additional context in comments.

Comments

0

One solution would be to have a commentTextStore object, where the keys(properties) are the commentIds and then you have each question text area write to the value corresponding the commentId.

Comments

0

Just set commentText as an object:

var QuestionList = React.createClass({
    getInitialState: function () {
        return {
            commentText: {},
        }
    },

    onUpdateComments: function (e) {

        // Note that e.target.name is question.id
        var target = e.target;
        this.state.commentText[target.name] = target.value;
        this.forceUpdate();
    },
    render: function () {
        var QuestionLines = this.props.questions.map(function(question) {

            var id = question.id; // store id

            return (
                <div key={id}>
                    <div>
                        <div>
                            {question.text}
                        </div>
                        <label>
                            <input type="radio" name={id} value = {id+'Y'}/>Yes
                        </label>
                        <label>
                            <input type="radio" name={id} value = {id+'N'}/>No
                        </label>
                    </div>
                    <div>
                        <textarea 
                            name = {id}
                            onChange = {this.onUpdateComments}
                            placeholder="Enter comments here" 
                            value={this.state.commentText[id]} />
                    </div>
                </div>
            );
        }, this);
        return (
            <div>
                {QuestionLines}
            </div>
        )
    }
});

See difference between onUpdateComments and value={this.state.commentText[id]}.

Note: If you use babel to compile your code, you can write onUpdateComments like that:

onUpdateComments: function (e) {

    // Note that e.target.name is question.id
    var target = e.target;
    this.setState(function(previousState) {
      return {
        commentText: {
          ...previousState.commentText, 
          [target.name]: target.value
        }
      }
    });
},

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.