9

I'm trying to build a proper react input checkbox select all component. The idea is that there is a component <InputCheckboxAll> and <InputCheckbox> and I'd be able to check the <InputCheckboxAll> and all of the <InputCheckbox> would be selected as well.

I'm having two issues.

  • If <InputCheckboxAll> is checked I can't unselect any of the <InputCheckbox>.
  • If all of the <InputCheckbox> are checked then <InputCheckboxAll> should be checked.

Here's the example.

var InputCheckboxAll = React.createClass({
  handleChange: function (event) {
    this.props.handleChange(event)
  },
  render: function () {
    return (
    <input
           type='checkbox'
           {...this.props}
           onChange={this.handleChange} />
    )
  }
})

var InputCheckbox = React.createClass({
  getInitialState: function () {
    return {
      checked: this.props.checked
    }
  },
  render: function () {
    var checkedValue = this.props.allChecked ? true : this.state.checked
    return (
    <input
           checked={checkedValue}
           type='checkbox'
           {...this.props}/>
    )
  }
})

var Test = React.createClass({
  getInitialState: function () { return {allChecked: false}; },
  handleChange: function (event) {
    var $elm = $(event.target)
    var checked = $elm.prop('checked')
    this.setState({
      allChecked: checked
    })
  },
  render: function () {
    return (
    <div>
      Select All: <InputCheckboxAll handleChange={this.handleChange}/><br/>
      <InputCheckbox allChecked={this.state.allChecked}/><br/>
      <InputCheckbox allChecked={this.state.allChecked}/><br/>
      <InputCheckbox allChecked={this.state.allChecked}/><br/>
    </div>
    )
  }
})

React.render(<Test/>, document.body)

4 Answers 4

16

I think there could be some modifications to your implementation to achieve the desired results in a more React'esque form.

What you should get rid of first, is the InputCheckboxAll checkbox class, and the allChecked prop of the InputCheckbox class. A checkbox is a relatively dumb element, it should not know about concepts such as Everything is selected.

Instead, the checkbox should be implemented as an item that is simply either checked or unchecked.

var InputCheckbox = React.createClass({
  getDefaultProps: function () {
    return {
      checked: false
    }
  },
  render: function () {
    return (
    <input
           checked={this.props.checked}
           type='checkbox'
           {...this.props}/>
    )
  }
})

The state of your app (concepts such as All Selected) should be managed from the main App, keeping lower level elements stateless. The state of the main app can simply represent the checked status of each of your checkboxes:

  getInitialState: function () { 
      return {
        // 3 checkboxes, all initialized as unchecked
        checked: [false, false, false]
      }; 
  },

Now, you can recreate the render function to draw 3 checkboxes, plus your select all checkbox. Each <InputCheckbox> can be binded to its own data in the this.state.checked array. When the <Inputcheckbox> changes, we bind an index to the change handler, so we know which array element to modify.

  render: function () {
    // Recalculate if everything is checked each render, instead of storing it
    var isAllChecked = this.state.checked.filter(function(c) {
        return c;
    }).length === this.state.checked.length;

    return (
    <div>
      Select All: <InputCheckbox 
               onChange={this.selectAll} 
               checked={isAllChecked}/><br/>

      <InputCheckbox 
               checked={this.state.checked[0]} 
               onChange={this.handleChange.bind(this, 0)}/><br/>
      <InputCheckbox 
               checked={this.state.checked[1]} 
               onChange={this.handleChange.bind(this, 1)}/><br/>
      <InputCheckbox 
               checked={this.state.checked[2]} 
               onChange={this.handleChange.bind(this, 2)}/><br/>
    </div>
    )
  }

You don't need to store any state related to All Selected. Instead, it would be better to recalculate if everything is selected or not during every render. When the Select All checkbox is checked, we simply set every element of this.state.checked to true.

This also has the advantage of when you manually select all the checkboxes, the select all checkbox will check itself.

Here's a sample implementation: https://jsfiddle.net/rsupvxry/

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

11 Comments

This is really helpful! Thank you so much for putting this together. I have one concern with this as you've authored it. I'd like to make this checkbox more modular, so I can use it in many different projects. I don't want to carry around these event handlers every time. I can use a mixin, but apparently they're dead, and that isAllChecked var gets in the way. Also having to define the state for each elm sees redundant. How would you port this out even further to be plug-and-play modular?
Or does React simply not allow it?
What type of functionality do you want to make modular? Do you want to have a group of checkboxes, that come with an accompanying select all checkbox? Or do you want to have a SelectAllCheckbox that you can wrap around other basic checkboxes? That way, you could handle the select all logic within that element.
I'm not sure the exact difference, I'm assuming the latter. I want the exact functionality we have here, I don't wants elements anything nested within each other. I'd like too just tuck all of the functionality created here away somewhere so it's easy to use.
There is a modular component for input at github.com/calitek/ReactPatterns under React.13.Common/FormInputs.
|
1

I came across to this thread very late. Below solution works for me with below structure.

There are 3 components which makes this feature clean and reusable.

  1. CheckBox - Reusable Component
  2. CheckBoxList - Reusable Component
  3. CityList - End level where you can create states list or any list by cloning this.

Stack Blitz with Module - https://stackblitz.com/edit/react-check-box-list

Standlone Code is below

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>React: Select All or DeSelect All</title>
        <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
        <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
        <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
        <script type="text/babel">
            function CheckBox({name, value, tick, onCheck}) {
                return (
                    <label>
                        <input
                            name={name}
                            type="checkbox"
                            value={value}
                            checked={tick || false}
                            onChange={onCheck}
                        />
                        {value}
                    </label>
                );
            }

            function CheckBoxList ({options, isCheckedAll, onCheck}) {
                const checkBoxOptions = (
                    <div className="checkbox-list">
                        {options.map((option, index) => {
                            return (
                                <CheckBox key={index} name={option.name} value={option.value} tick={option.checked} onCheck={(e) => onCheck(option.value, e.target.checked)} />
                            );
                        })}
                    </div>
                );

                return (
                    <div className="checkbox-list">
                        <CheckBox name="select-all" value="ALL" tick={isCheckedAll} onCheck={(e) => onCheck('all', e.target.checked)} />
                        {checkBoxOptions}
                    </div>
                );
            }

            class CityList extends React.Component {
                constructor(props) {
                    super(props);

                    this.state = {
                        isAllSelected: false,
                        checkList: [
                            {
                                name: "city",
                                value: "bangalore",
                                checked: false,
                            },
                            {
                                name: "city",
                                value: "chennai",
                                checked: false,
                            },
                            {
                                name: "city",
                                value: "delhi",
                                checked: false,
                            }
                        ]
                    };
                }

                onCheckBoxChange(checkName, isChecked) {
                    let isAllChecked = (checkName === 'all' && isChecked);
                    let isAllUnChecked = (checkName === 'all' && !isChecked);
                    const checked = isChecked;

                    const checkList = this.state.checkList.map((city, index) => {
                        if(isAllChecked || city.value === checkName) {
                            return Object.assign({}, city, {
                                checked,
                            });
                        } else if (isAllUnChecked) {
                            return Object.assign({}, city, {
                                checked: false,
                            });
                        }

                        return city;
                    });

                    let isAllSelected = (checkList.findIndex((item) => item.checked === false) === -1) || isAllChecked;

                    this.setState({
                        checkList,
                        isAllSelected,
                    });

                }

                render() {
                    return (<CheckBoxList options={this.state.checkList} isCheckedAll={this.state.isAllSelected} onCheck={this.onCheckBoxChange.bind(this)} />);
                }
            }

            ReactDOM.render(
                <CityList />,
                document.getElementById('root')
            );
        </script>
    </head>
    <body>
        <div id="root"></div>
    </body>
</html>

Comments

1

There is a simple package that solves this problem grouped-checkboxes.

In your case the render function will look like this:

render: function () {
  return (
    <CheckboxGroup>
      Select All: <AllCheckerCheckbox /><br/>
      <Checkbox id="option-0" onChange={this.handleChange.bind(this, 0)}/><br/>
      <Checkbox id="option-1" onChange={this.handleChange.bind(this, 1)}/><br/>
      <Checkbox id="option-2" onChange={this.handleChange.bind(this, 2)}/><br/>
    </CheckboxGroup>
  )
}

More examples see Codesandbox example

1 Comment

Please be careful with linking to your own content on different sites, you don't want to be a spammer. You should be including the majority of the content here, and use the link only as a reference.
0

I made the check all option how below:

JS code:

 const checkAll = (e) => {

  var value  = false

  if(e.target.checked){
    value = true;
  }
  
  Array.from(document.querySelectorAll("input[name="+name+"]"))
       .forEach((checkbox) => {
        document.getElementById(checkbox.id).checked = value;
       });
 }

HTML code (Check All):

 <input type="checkbox" name="all" onChange={checkAll} />

HTML code (Options):

 <input type="checkbox" name={name} id={name+index} value={obj.id} />

The options was created using the loop where the id is unique for such checkbox.

2 Comments

Sorry if I asked a stupid question, is it for react framework? To me it doesn't look like for react components.
@JasonLiu yes it is React, I created it inside a Hook function where the checkAll() is a function that can called when you click on the check all input.

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.