I found an interesting question on Stack Overflow. It involves having two main checkboxes and 4 checkboxes for the 2 main checkboxes group.
I'm new to React and wanted to try this with React. I have two groups of checkboxes, one which shows a list of fruits and another which shows a list of vegetables.
The structure looks like this:
- fruits - - Apple - - Orange - - Pineapple - - Mango - vegetables - - Tomatoes - - Cucumbers - - Carrots - - Avocados
Checking the fruits checkbox will check all of the fruit checkboxes. Unchecking one of the fruits, will remove the fruits checkbox from being checked. Same goes for vegetables.
As you can see in the fiddle, this is working but it involved a lot of hacks. How can this be refactored if at all?
var ItemTree = React.createClass({
getDefaultProps: function() {
return {
list: {},
};
},
getInitialState: function() {
var checklist = [];
$.each(this.props.list, function(groupName, itemList) {
var items = $.map(itemList, function(name) {
return {
name: name,
checked: false,
};
});
checklist.push({
name: groupName,
children: items,
checked: false,
});
});
return {
checklist: checklist,
};
},
This code checks the main checkboxes and updates the children:
handleCheckGroup: function(index) {
var checklist = this.state.checklist;
checklist[index].checked = !checklist[index].checked;
var children = checklist[index].children;
Checking the child checkboxes and updating the state:
$.each(children, function(i) {
checklist[index].children[i].checked = true;
})
this.setState({
checklist: checklist,
})
},
For when you click on the child checkboxes:
checkChild: function(name, c, index) {
var checklist = this.state.checklist;
I'm trying to find the checkbox group that contains the name of my checkbox.
var groups = checklist.filter(function(group) {
return group.children.some(function(child) {
return child.name == name;
});
});
var isChecked = groups[0].children[c].checked;
This toggles the checkbox on and off:
if (!isChecked) {
groups[0].children[c].checked = true;
}
else {
groups[0].children[c].checked = false;
}
This counts the number of checkboxes that are checked:
var countChecked = groups[0].children.filter(function(child) {
return child.checked;
}).length;
If there are 4 checked, the main checkbox will automatically be checked:
groups[0].checked = countChecked == 4;
this.setState({
checklist: checklist,
})
groups[0].children[index].checked = true;
},
render: function() {
return (
<div>
{$.map(this.state.checklist, function(item, itemIndex) {
return (
<div key={item.name}>
{/* checking the main checkbox should automatically check all of the sub-items */}
<label>
<input type="checkbox" checked={item.checked} onChange={this.handleCheckGroup.bind(null, itemIndex)} /> <strong>{item.name}</strong>
</label>
<div style={{marginLeft: 20}}>
{$.map(item.children, function(childItem, childIndex) {
return (
<div key={childItem.name}>
{/* if at least one of the sub-items are unchecked then the main/group checkbox should also be unchecked automatically */}
<label>
<input type="checkbox" checked={childItem.checked} onChange={this.checkChild.bind(null, childItem.name, childIndex)} />
{' '}
{childItem.name}
</label>
</div>
);
}.bind(this))}
</div>
</div>
);
}.bind(this))}
</div>
);
}
});
jQuery(function($) {
var itemList = {
Fruits: ['Apple', 'Orange', 'Pineapple', 'Mango'],
Vegetables: ['Tomatoes', 'Cucumbers', 'Carrots', 'Avocados']
};
ReactDOM.render(<ItemTree list={itemList} />, $('#component').get(0));
});
The problem is I'm thinking of this in a JavaScript way, probably not in a React way.