Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to select all checkboxes in React?

I have this module:

import React, { Component } from 'react'
import EmailListItem from './EmailListItem'
import { createContainer } from 'meteor/react-meteor-data'
import { Emails } from '../../../../../imports/collections/emails/Emails'

class EmailList extends Component {
  constructor (props) {
    super(props)
    this.state = {
      selectedEmails: new Set(),
      checked: false
    }
  }

  handleSelectedEmails (selectedEmail, checked) {
    let selectedEmails = this.state.selectedEmails
    if (checked) {
      selectedEmails.add(selectedEmail)
    } else {
      selectedEmails.delete(selectedEmail)
    }
    this.setState({selectedEmails})
    console.log('selectedEmails', this.state.selectedEmails)
  }
  removeSelected () {
    const selectedEmails = Array.from(this.state.selectedEmails)
    Meteor.call('emails.remove', selectedEmails, (err, result) => {
      if (err) console.log(err)
      if (result) console.log(result)
    })
  }
  checkedClick () {
    this.setState({checked: !this.state.checked})
    console.log('chcekedClick')
  }
  renderList () {
    console.log(this.props)
    return this.props.emails.map(email => {
      console.log(email)
      const { name, opr, ctr, _id } = email
      const createdAt = email.createdAt.toDateString()
      const link = `/dashboard/emailpreview/${_id}`
      return (
        <EmailListItem
          selecetedAllEmails={this.state.checked}
          handleSelectedEmails={this.handleSelectedEmails.bind(this)}
          name={name}
          createdAt={createdAt}
          opr={opr}
          ctr={ctr}
          link={link}
          key={email._id}
          id={email._id} />
        )
    })
  }
  render () {
    // TODO: make checks with state
    return (
      <div className="email_list">
        <table>
          <thead>
            <tr>
              <td><input onChange={this.checkedClick.bind(this)} type="checkbox" checked={this.state.checked} /></td>
              <td>Title<button onClick={this.removeSelected.bind(this)} className="btn btn-danger">Remove</button></td>
              <td>Dates</td>
              <td>Open Rates</td>
              <td>CTA</td>
            </tr>
          </thead>
          <tbody>
            {this.renderList()}
          </tbody>
        </table>

      </div>
  )
  }
}

export default createContainer(() => {
  Meteor.subscribe('emails')
  return { emails: Emails.find({}).fetch() }
}, EmailList)

And it renders this module

import React, { Component } from 'react'
import { Link } from 'react-router'

class EmailListItem extends Component {
  constructor (props) {
    super(props)
    this.state = {
      checked: false
    }
  }

  checkedClick () {
    this.setState({checked: !this.state.checked})
    console.log('chcekedClick')
  }

  componentDidUpdate () {
    console.log('componentDidUpdate')
    const { myCheckbox } = this.refs
    console.log('myCheckbox', myCheckbox)
    console.log('myCheckbox.name', myCheckbox.name)
    console.log('myCheckbox.checked', myCheckbox.checked)
    if (this.props.selecetedAllEmails) {
      console.log('componentDidUpdate IF')
      this.checkedClick()
      this.props.handleSelectedEmails(myCheckbox.name, myCheckbox.checked)
    }
  }
  render () {
    console.log('_id', this.props.id)
    return (
      <tr>
        <td><input ref="myCheckbox"
          onChange={(event) => {
            this.checkedClick()
            this.props.handleSelectedEmails(event.target.name, event.target.checked)
          }}
          checked={this.state.checked}
          type="checkbox" name={this.props.id} /></td>
        <td><Link to={this.props.link}>{this.props.name}</Link></td>
        <td>{this.props.createdAt}</td>
        <td>Open Rates</td>
        <td>CTA</td>
      </tr>
    )
  }
}

export default EmailListItem

As you can see, for each email item I have a checkbox. I can select a few checkboxes, and click that remove button which will call remove my selected items. Now in the top I have a checkbox which should select all the checkboxes. My solution to this was to store the global checkbox checked and pass it as a prop to all the items. Then in the items I perform a check on componentDidUpdate and if the global checkbox is selected then I check that item as well. But this results in an infinite loop. What would be the best solution here?

like image 614
Hayk Safaryan Avatar asked Jan 05 '23 15:01

Hayk Safaryan


1 Answers

While some of the answers provided the specific functionality of selecting all the checkboxes, I needed also common functionalities like deselecting all, selecting all then deselecting some, when manually selecting all the select all box checks on as well etc... So I wrote all of that and post it as an answer here. Thanks to everyone who replied. This code is based on Mayank Shuklas answer. Note that it may not still be perfect as I didn't properly tested it yet and definitely it needs some refactoring.

import React, { Component } from 'react'
import EmailListItem from './EmailListItem'
import { createContainer } from 'meteor/react-meteor-data'
import { Emails } from '../../../../../imports/collections/emails/Emails'

class EmailList extends Component {
  constructor (props) {
    super(props)
    this.state = {
      selectedEmails: new Set(),
      checked: false
    }
  }

  handleSelectedEmails (allSelected, individualSelected, selectedEmail, checked) {
    console.log('allSelected', allSelected)
    console.log('individualSelected', individualSelected)
    console.log('selectedEmail', selectedEmail)
    console.log('checked', checked)
    let selectedEmails = this.state.selectedEmails
    if (allSelected && !individualSelected) {
        this.props.emails.forEach((email) => {
          selectedEmails.add(email._id)
        })
    } else if (!allSelected && !individualSelected) {
      selectedEmails.clear()
    } else if (individualSelected) {
      if (checked) {
        selectedEmails.add(selectedEmail)
        if (selectedEmails.size === this.props.emails.length) {
          this.checkAll()
        }
      } else {
        selectedEmails.delete(selectedEmail)
        this.setState({checked})
      }
    }
    this.setState({selectedEmails})
    console.log('selectedEmails', this.state.selectedEmails)
  }
  removeSelected () {
    const selectedEmails = Array.from(this.state.selectedEmails)
    Meteor.call('emails.remove', selectedEmails, (err, result) => {
      if (err) console.log(err)
      if (result) console.log(result)
    })
  }
  checkAll () {
    this.setState({checked: !this.state.checked})
    console.log('chcekedClick', this.state.checked)
    this.handleSelectedEmails(!this.state.checked, false)
  }
  renderList () {
    console.log(this.props)
    return this.props.emails.map(email => {
      // console.log(email)
      const { name, opr, ctr, _id } = email
      const createdAt = email.createdAt.toDateString()
      const link = `/dashboard/emailpreview/${_id}`
      return (
        <EmailListItem
          handleSelectedEmails={this.handleSelectedEmails.bind(this)}
          name={name}
          createdAt={createdAt}
          opr={opr}
          ctr={ctr}
          link={link}
          key={email._id}
          id={email._id}
          value={this.state.checked || this.state.selectedEmails.has(email._id)} />
        )
    })
  }
  render () {
    // TODO: make checks with state
    return (
      <div className="email_list">
        <table>
          <thead>
            <tr>
              <td><input onChange={this.checkAll.bind(this)} type="checkbox" checked={this.state.checked} /></td>
              <td>Title<button onClick={this.removeSelected.bind(this)} className="btn btn-danger">Remove</button></td>
              <td>Dates</td>
              <td>Open Rates</td>
              <td>CTA</td>
            </tr>
          </thead>
          <tbody>
            {this.renderList()}
          </tbody>
        </table>

      </div>
  )
  }
}

export default createContainer(() => {
  Meteor.subscribe('emails')
  return { emails: Emails.find({}).fetch() }
}, EmailList)

And the EmailListItem

import React, { Component } from 'react'
import { Link } from 'react-router'

class EmailListItem extends Component {
  render () {
    console.log('_id', this.props.id)
    return (
      <tr>
        <td><input ref="myCheckbox"
          onChange={(event) => {
            this.props.handleSelectedEmails(false, true, event.target.name, event.target.checked)
          }}
          checked={this.props.value}
          type="checkbox" name={this.props.id} /></td>
        <td><Link to={this.props.link}>{this.props.name}</Link></td>
        <td>{this.props.createdAt}</td>
        <td>Open Rates</td>
        <td>CTA</td>
      </tr>
    )
  }
}

export default EmailListItem
like image 119
Hayk Safaryan Avatar answered Jan 07 '23 19:01

Hayk Safaryan