0

When building an form that takes user input of number ratings on a set of items evaluated by a set of attributes, how can I set their index accordingly and what's the best way to capture/update all the inputs in the state such that I can compare their total later? The code can be found below or in sandbox Thanks for any inputs.

enter image description here

import React, { Component } from "react";

export default class Compare extends Component {
  constructor(props) {
    super(props);
    this.state = {
      items: props.items,
      attributes: props.attributes,
      itemAttributeScoreArray: [],
      eval: null
    };
  }

  _onChangefor = (index1, index2) => event => {
    console.log(event.target.value);
  };

  render() {
    return (
      <div>
        <table
          className="Table"
          style={{
            margin: "0 auto"
          }}
        >
          <thead>
            <tr>
              <th>Compare</th>
              <th>{this.state.items[0]}</th>
              <th>{this.state.items[1]}</th>
            </tr>
          </thead>
          <tbody>
            {this.state.attributes.map((attribute, index1) => (
              <tr>
               {attribute}
               {this.state.items.map((item, index2) =>
               <td>
                <input 
                  key = {index1+''+index2}
                  type="number"
                  onChange={this._onChangefor((index1, index2))}
                  />
                </td>)}
              </tr>
            ))}
          </tbody>

        </table>
      </div>
    );
  }
}
1
  • 1
    Using index is not the best practice, since it is not unique value eg. when you add items to array or remove them. Look at your attributes array and use unique value from there if it exists, your each attribute in attributes array is unique, so use them as key instead, if none of the values are unique, i would recommend using index as the last choice Commented Jul 11, 2019 at 5:40

2 Answers 2

1

You want to make a Key, Value pair in your compare class from the props and it will be much easier to handle the state. So, your key value should look like,

this.state = {
    ...
    "model": {
        "Location": {
            "Choice1": "",
            "Choice2": ""
        },
        "Time": {
            "Choice1": "",
            "Choice2": ""
        },
        "Environment": {
            "Choice1": "",
            "Choice2": ""
        }
    }
}

And modify the onChange event to send the appropriate attribute and item value like,

 onChange={(e) => this._onChangefor(e, attribute, item)}

Here is the full list of changes I have make and is working just file

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

Comments

1

You can assume that attribute and item is state that keep your master data, so you need a transaction state to keep your transaction, so I tried to add a state called "transaction" to keep your input value,

constructor(props) {
super(props);
this.state = {
  items: props.items,
  attributes: props.attributes,
  itemAttributeScoreArray: [],
  eval: null,
  transaction: []
};}

then add value to the transaction on componentDidMount,

componentDidMount(){
let transaction = [];
this.props.attributes.map((attr,idx) =>{
  let _attributes = { attribute: attr, item:[] }
  this.props.items.map((_attr,_idx) =>{
    let _temp = _attr;
    _attributes.item.push({name: _attr, value: 0});
  })
  transaction.push(_attributes);  
})
this.setState({transaction: transaction})}

then you may render your input like this

<tbody>
        {this.state.transaction.map((attribute, index1) => (
          <tr>
           {attribute.attribute}
           {attribute.item.map((item, index2) =>
           <td>
            <input 
              key = {index1+''+index2}
              type="number"
              value={item.value}
               onChange={this._onChangefor(attribute.attribute, index2)}
              />
            </td>)}
          </tr>
        ))}
      </tbody>

and the last thing is you need to handle the value of input as the value of your transaction in _onChangefor

_onChangefor = (index1, index2) => event => {
 let _val = event.target.value;
  this.setState(
        state => {
          const list = this.state.transaction.find(result => result.attribute === index1).item.map((items, j) => {
            if (j === index2) {
              items.value = _val;
              return items;
            } else {
              return items;
            }

          });
          return {
            list,
          };
        }
          );};

thats it, let me know if you have any further question, (y)

2 Comments

any reason componentDidMount is needed here?
at the first time you declare the transaction state, its value was empty :[], but u need to add value to used it, the best way to add value to transaction state is when the component mount for the first time, thats why i use componentDidMount. The main purpose of component did mount here is to add the transaction set some value "this.setState({transaction: transaction})"

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.