I created a custom checkbox list in React using Material-UI-Next for use at my organization. We want to add a "none of the below" option where the None option clears the checkboxes below but also persists to the DB as an explicit "None of the below" is different than just not having checked any of the checkboxes below, yet.
The checkbox list worked fine and when I explicitly passed {true} or {false} to the "None" checkbox, it was checked or unchecked as desired. I debugged and found that the noneChecked variable has the correct value but the "checked-ness" of the "noneCheck" checkbox isn't always matching the value of the noneChecked variable. :(
Also, we can't check "None" when none of the options below are checked. And we want to be able to do this. Here is my code:
import React, { Component } from 'react';
import { Checkbox, FormGroup, FormControlLabel, FormLabel } from "material-ui";
import compose from 'recompose/compose';
import { withStyles } from 'material-ui/styles';
var _ = require('lodash');
//overwrite component styles
//injected into component
const styles = theme => ({
root: {
backgroundColor: 'yellow',
fontFamily: 'Roboto'
}
});
//injected into material-ui element. e.g style={style}
const style = {
color: 'yellow'
};
export class CustomCheckBoxList extends Component
{
constructor(props){
console.log("Constructing CheckBoxList: props =", props)
super(props);
this.state = {
options: [],
noneChecked: null
}
this.applyChecked.bind(this);
this.handleCheckboxChange.bind(this);
};
handleCheckboxChange(event, option) {
let thisOption = {...option}
let valuesToReturn = []
let objectUpdates = {};
if (this.props.values != null)
{
valuesToReturn = [...this.props.values]
}
let optionChecked = thisOption.isChecked
let thisOptionWithoutChecked = _.omit(thisOption, ['isChecked'])
if(optionChecked)
{
_.pullAllBy(valuesToReturn, [thisOptionWithoutChecked], 'id')
objectUpdates[this.props.name] = valuesToReturn;
}
else
{
this.state.noneChecked = false;
valuesToReturn.push(thisOptionWithoutChecked)
objectUpdates[this.props.name] = valuesToReturn;
objectUpdates[this.props.noneName] = false;
}
this.props.valueChanged(objectUpdates);
}
handleNoneCheck(event) {
let objectUpdates = {};
if(this.state.noneChecked == null || this.state.noneChecked == false)
{
this.state.noneChecked = true;
objectUpdates[this.props.name] = [];
objectUpdates[this.props.noneName] = true;
}
else
{
this.state.noneChecked = false;
objectUpdates[this.props.noneName] = true;
}
this.props.valueChanged(objectUpdates);
}
applyChecked(option)
{
let optionIndex = _.findIndex(this.props.values, ['id', option.id])
return {...option, isChecked: (optionIndex > -1)}
}
getOptionName(option){
if (this.props.currentLanguage == 'en'){
return option.nameEng;
}else if (this.props.currentLanguage == 'fr'){
return option.nameFra;
}else{
return null;
}
}//END OF METHOD
render()
{
this.state = {
options: [],
noneChecked: null
}
if (this.props.options != undefined)
{
this.state.options = this.props.options.map(this.applyChecked.bind(this));
}
this.state.noneChecked = this.props.noneChecked;
console.log('this.state.noneChecked= ', this.state.noneChecked);
var noneChecked = this.state.noneChecked;
return (
<div>
<FormLabel> <b>{this.props.label}</b> {this.props.secondaryLabel}</FormLabel>
<FormGroup row={this.props.row}>
<FormControlLabel control= {
<Checkbox id="noneCheck"
checked = {noneChecked}
onChange={(event) => this.handleNoneCheck(event)}/>
}
label={this.props.noneLabel} />
{
this.state.options.map((option) =>{
let thisOption = {...option}
let optionName = this.getOptionName(option);
return (
<FormControlLabel key={thisOption.id}
control= {
<Checkbox checked={thisOption.isChecked}
onChange={(event) => this.handleCheckboxChange(event, option)}/>
}
label={optionName} />
);
})
}
</FormGroup>
</div>
);
}
}
export default withStyles(styles)(CustomCheckBoxList);
Any advice?