4

I tried to control dynamic checkbox rendered from my array. My problem is i have multiple checkbox but i only have one state in my constructor. Is there any others method on how to control dynamic fields/items without

Below is my code :

  onAddingItem = (item) =>{
    var self = this;
    const value = item.target.type === 'checkbox' ? item.target.checked : item.target.value;
    var newArray = self.state.product.slice();
    if(item.target.checked){
        newArray.push(item.target.value);
        self.setState({addProducts:value, product:newArray})
    } else {
      newArray.splice(item.target.value, 1); //remove element
      self.setState({addProducts:value, product:newArray}); //update state
    }
  }

  render(){
    var self = this;
    const {title, photo, photoHeight, photoWidth, showPhoto, editorState, description, editorData, productsList} = this.state;
    const product_list = productsList.map((index, i) =>
      <tr key={i+1}>
        <td>{i+1}</td>
        <td>{index.name}</td>
        <td>
            <div class="checkbox checkbox-circle checkbox-color-scheme">
                <label class="checkbox-checked">
                    <input type="checkbox" value={index.name} checked={self.state.addProducts} onChange={this.onAddingItem}/> <span class="label-text">Add ?</span>
                </label>
            </div>
        </td>
      </tr>
    );

Whenever i checked one of the checkbox. All the other checkbox also being checked. As you see i want to add the value of the checkbox into an array when its checked and remove the existing value from array when the checkbox is unchecked.

3 Answers 3

8

It will be better if you set an isChecked property for your products array.

Here we are:

class App extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      productsList :[
        {name: 'USS Seawolf class', isChecked: false},
        {name: 'USS Skipjack', isChecked: false},
        {name: 'USS Lafayette', isChecked: false},
        {name: 'USS Ohio class', isChecked: false},
      ]
    }
  }
  
  onAddingItem = (i) => (event) => {
    this.setState((state, props) => {
      state.productsList[i].isChecked = !state.productsList[i].isChecked;
      return {
        productsList: state.productsList
      }
    })
  }

  render() {
    let {productsList} =  this.state;
    return (
      <table>
        <tbody>
          { productsList.map((product, i) =>{
            return(
              <tr key={i+1}>
                <td>{i+1}</td>
                <td>{product.name}</td>
                <td>
                    <div class="checkbox checkbox-circle checkbox-color-scheme">
                        <label class="checkbox-checked">
                            <input type="checkbox" value={product.name} checked={product.isChecked} onChange={this.onAddingItem(i)}/> <span class="label-text">Add ?</span>
                        </label>
                    </div>
                </td>
            </tr>
            )
          })}
          
        </tbody>
      </table>
    )
  }
}

ReactDOM.render( <
  App / > ,
  document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app">
  <!-- This element's contents will be replaced with your component. -->
</div>

And you can getisChecked elements by filter():

let selectedProductsArray = this.state.productsList.filter((product, i)=>{
   return product.isChecked
});
Sign up to request clarification or add additional context in comments.

1 Comment

I believe you are mutating the state here: state.productsList[i].isChecked = !state.productsList[i].isChecked;
1

I agree with Emad on adding a property inside each object to control each checkbox, however make sure you don't mutate the state when updating those values.

class App extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      productsList: [{ name: "Product A", isAdded: false }, { name: "Product B", isAdded: false }, { name: "Product C", isAdded: false }],
      addedProducts: []
    }
  }

  onAddingItem = (item) => {
    const isChecked = item.target.checked;
    const value = item.target.value;

    this.setState(prevState => ({ productsList: prevState.productsList.map(product => product.name === value ? { ...product, isAdded: isChecked } : product) }));

    if (isChecked)
      this.setState(prevState => ({addedProducts: [...prevState.addedProducts, value] }));
    else {
      const newAddedProducts = this.state.addedProducts.filter(product => product !== value)
      this.setState({ addedProducts: newAddedProducts });
    }
  }
  
  render() {
    const { productsList } = this.state;
    const product_list = productsList.map((index, i) =>
      <tr key={i + 1}>
        <td>{i + 1} - </td>
        <td>{index.name}</td>
        <td>
          <div class="checkbox checkbox-circle checkbox-color-scheme">
            <label class="checkbox-checked">
              <input type="checkbox" value={index.name} checked={this.state.productsList[i].isAdded} onChange={this.onAddingItem} /> <span class="label-text">Add ?</span>
            </label>
          </div>
        </td>
      </tr>
    );

    return (
      <div>
        <table>
          <tbody>
            {product_list}
          </tbody>
        </table>
        <div style={{ marginTop: "20px" }}>Added Products: {this.state.addedProducts.join(', ')}</div>
      </div>
    )
  }
}

ReactDOM.render( <
  App / > ,
  document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app">
  <!-- This element's contents will be replaced with your component. -->
</div>

Comments

0

You are setting checked to self.state.addProducts for each checkbox. This property expects a boolean so any truthy value will cause all of the boxes to be checked.

checked should only be true if its value is in self.state.product.

Edit: maybe something like this? checked={self.state.product.includes(item.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.