最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React material ui select all checkbox - Stack Overflow

programmeradmin3浏览0评论

I need to make that when selecting checkbox Select All, the rest of the checkboxes from the list are checked, and each checkbox can be selected separately. But when select one of the checkboxes does not checked the previous checkbox.

sandbox

const options = [ 'Selected Item 1', 'Selected Item 2', 'Selected Item 3'];

export default function App() {

  const [selected, setSelected] = useState([]);
  const isAllSelected = 
      options.length > 0 && selected.length === options.length;

  const handleChange = (event) => {
    const value = event.target.value;
    console.log(value)
    if (value === "all") {
      setSelected(selected.length === options.length ? [] : options);
      return;
    }
    setSelected(value);
  };  

  const listItem = options.map((option) => {        
    return (
        <div key={option}>
          <Checkbox 
            value={option}
            onChange={handleChange} 
            checked={selected.includes(option) } />
          <span>{option}</span>
        </div>
    )
  })

  return (
    <div style={{ display: 'flex', alignItems: 'center', margin: 10 }}>
        <Checkbox 
          value='all' 
          onChange={handleChange} 
          checked={isAllSelected} 
          />
        <span> Select All</span>
        {listItem}
    </div>
  );
}

I need to make that when selecting checkbox Select All, the rest of the checkboxes from the list are checked, and each checkbox can be selected separately. But when select one of the checkboxes does not checked the previous checkbox.

sandbox

const options = [ 'Selected Item 1', 'Selected Item 2', 'Selected Item 3'];

export default function App() {

  const [selected, setSelected] = useState([]);
  const isAllSelected = 
      options.length > 0 && selected.length === options.length;

  const handleChange = (event) => {
    const value = event.target.value;
    console.log(value)
    if (value === "all") {
      setSelected(selected.length === options.length ? [] : options);
      return;
    }
    setSelected(value);
  };  

  const listItem = options.map((option) => {        
    return (
        <div key={option}>
          <Checkbox 
            value={option}
            onChange={handleChange} 
            checked={selected.includes(option) } />
          <span>{option}</span>
        </div>
    )
  })

  return (
    <div style={{ display: 'flex', alignItems: 'center', margin: 10 }}>
        <Checkbox 
          value='all' 
          onChange={handleChange} 
          checked={isAllSelected} 
          />
        <span> Select All</span>
        {listItem}
    </div>
  );
}
Share asked Jul 5, 2021 at 5:09 stepbystepstepbystep 3913 gold badges8 silver badges23 bronze badges 3
  • you want to implement multi checkbox selection right? – Rahul Kumar Commented Jul 5, 2021 at 5:15
  • @RahulKumar yes absolutly – stepbystep Commented Jul 5, 2021 at 5:17
  • added the answer below – Rahul Kumar Commented Jul 5, 2021 at 6:26
Add a ment  | 

4 Answers 4

Reset to default 0

When you click on checkboxes other than "all" checkbox, you are just setting your selected state to that value: setSelected(value);. There are 2 problems with this code - 1) In your case the selected state should always be an array, but you are changing that to a string. 2) you are disregarding any previous values that might be added to the selected state. You must figure out if the clicked checkbox was already in the selected state or not. if not, you should add it to the state. If it was then you should remove it from the state. Here is how you can do this:

const handleChange = (event) => {
    const value = event.target.value;
    console.log(value)
    if (value === 'all') {
      setSelected(selected.length === options.length ? [] : options);
      return;
    }
    if (selected.indexOf(value) !== -1) { // if value already present
      const newSelected = selected.filter((s) => s !== value );
      setSelected(newSelected);
    } else { // if value not present
      setSelected([ ...selected, value ]);
    }
}

You can make a data-structure like [{data:any, selected: boolean}, {data:any, selected: boolean}] Then you loop through it and display them as

  const [items, setItems] = useState<Asset[]>([]);

  const [select, setSelect] = useState(false)

  const handleChange = (index, checked) => {
   
     if(select && !checked) setSelect(false)

     const itemRef = [...items];

     itemRef[index].selected = checked

     setItems([...itemRef]);
  } 

  const handleChangeAll = (checked) => {
     const itemRef = [...items];
    
     itemRef.forEach((_item, i) => {
        itemRef[i].selected = checked

     })

     setSelect(checked)
 
     setItems([...itemRef]);
  } 

   
  ------
   All selection checkbox
 
   <Checkbox
       checked={select}
       onChange={(_e, checked) => handleChangeAll(checked)} 
      />

  ** items **
  
  items.map((item, i) => (
     <Checkbox
       key={item.data.id} 
       checked={item.selected}
       onChange={(_e, checked) => handleChange(index, checked)}  
      />

  ))


Once it is done if you want to extract the selected data, you can just apply the filter method based on item.selected from items array,

Need to update selected options array instead of assigning the value directly inside handleChange method. So first check if selected list contains the checked option if it contains then remove it, otherwise add it to the selected list.

 const handleChange = (event) => {
    const value = event.target.value;
    console.log(value);
    if (value === "all") {
      setSelected(selected.length === options.length ? [] : options);
      return;
    }
    // added below code to update selected options
    const list = [...selected];
    const index = list.indexOf(value);
    index === -1 ? list.push(value) : list.splice(index, 1);
    setSelected(list);
};

Sandbox link here

Your logic for selecting all the checkboxes works quite well. As for the problem of selecting a checkbox separately you can fix this with the following code.

First we check if the value is already in the selected array, if not we can simply return a new array with the prevSelected and the new one. If the value already exists in the prevSelected we can remove it using the filter method.

const handleChange = (event) => {
  const value = event.target.value;
  if (value === "all") {
    setSelected(selected.length === options.length ? [] : options);
    return;
  }
  setSelected((prevSelected) => {
    if (!prevSelected.includes(value)) return [...prevSelected, value];
    return prevSelected.filter((option) => option !== value);
  });
};

Little side note, it's not remended to create your listItem array as a variable inside your ponent. As this creates a new array of checkboxes everytime your states change. You could simply map over them in your return statement.

return (
  <div style={{ display: "flex", alignItems: "center", margin: 10 }}>
    <Checkbox value="all" onChange={handleChange} checked={isAllSelected} />
    <span> Select All</span>
    {options.map((option) => {
      return (
        <div key={option}>
          <Checkbox value={option} onChange={handleChange} checked={selected.includes(option)} />
          <span>{option}</span>
        </div>
      );
    })}
  </div>
);
发布评论

评论列表(0)

  1. 暂无评论