Reputation: 138
Im building a CheckAllBoxes component in Reactjs. I have a list of items
fruits = {orange, apple, grape}
A general <SelectBox />
component to display and toggle the HTML checkbox
I need to build a <Fruits />
component to list all the fruits and each of item has its own <SelectBox />
Then I need to build a <SelectAll />
component which has a <SelectBox />
and when it is checked, it will toggle all the <CheckBox />
of <Fruits />
If any fruit is unchecked again, then the <SelectAll />
should be unchecked too.
The result should look something like this:
How can I get the <SelectAll />
to control other checkboxes ?
Upvotes: 8
Views: 21495
Reputation: 8276
Here is the quick example on how you could do it:
import React, { Component } from 'react';
export default class SelectBox extends Component {
constructor() {
super();
this.handleClick = this.handleClick.bind(this);
this.state = {
allChecked: false,
checkedCount: 0,
options: [
{ value: 'selectAll', text: 'Select All' },
{ value: 'orange', text: 'Orange' },
{ value: 'apple', text: 'Apple' },
{ value: 'grape', text: 'Grape' }
]
};
}
handleClick(e) {
let clickedValue = e.target.value;
if (clickedValue === 'selectAll' && this.refs.selectAll.getDOMNode().checked) {
for (let i = 1; i < this.state.options.length; i++) {
let value = this.state.options[i].value;
this.refs[value].getDOMNode().checked = true;
}
this.setState({
checkedCount: this.state.options.length - 1
});
} else if (clickedValue === 'selectAll' && !this.refs.selectAll.getDOMNode().checked) {
for (let i = 1; i < this.state.options.length; i++) {
let value = this.state.options[i].value;
this.refs[value].getDOMNode().checked = false;
}
this.setState({
checkedCount: 0
});
}
if (clickedValue !== 'selectAll' && this.refs[clickedValue].getDOMNode().checked) {
this.setState({
checkedCount: this.state.checkedCount + 1
});
} else if (clickedValue !== 'selectAll' && !this.refs[clickedValue].getDOMNode().checked) {
this.setState({
checkedCount: this.state.checkedCount - 1
});
}
}
render() {
console.log('Selected boxes: ', this.state.checkedCount);
const options = this.state.options.map(option => {
return (
<input onClick={this.handleClick} type='checkbox' name={option.value} key={option.value}
value={option.value} ref={option.value} > {option.text} </input>
);
});
return (
<div className='SelectBox'>
<form>
{options}
</form>
</div>
);
}
}
I'm sorry for the ES6 example. Will add ES5 example when I find more time, but I think you can get the idea on how to do it. Also you definitely want to break this down into 2 components. Then you would just pass your options as props to the Child component.
Upvotes: 7
Reputation: 866
I would recommend reading Communication between Components
Now in your example you have a communication between two components that don't have a parent-child relationship. In these case you could use a global event system. Flux works great with React.
In your example I would make FruitStore
with the component Fruit
listening to store. The FruitStore
contains a list with all fruits and if they are selected or not. Fruit
will saves it's content with setState()
.
Fruit
passes to it's children their status per props. example: <CheckBox checked={this.state.fruit.checked} name={this.state.fruit.name}/>
Checkbox
should fire when clicked a FruitAction.checkCheckbox(fruitName)
.
The FruitStore
will then update the Fruit
component and so on.
It take some time to get into this unidirectional architecture, but it's worth learning it. Try starting with the Flux Todo List Tutorial.
Upvotes: 0