3

I'm wanting to do a checkbox functionality, where you click on the parent checkbox and it checks all the children. But you can also select an individual checkbox. I'm trying to do this using Chakra UI, but in the documentation they do it using just two checkboxes. In my case, I'm using map to iterate, so the problem that occurs is that I can only check them all, but I can't uncheck an individual checkbox. How would I resolve this?

 import NextLink from 'next/link';
import { useState } from 'react';
import { queryClient } from '../../services/queryClient';
import { api } from '../../services/api';

export default function UserList() {
  const [page, setPage] = useState(1);
  const [checkedItems, setCheckedItems] = useState([false, false]);

  const allChecked = checkedItems.every(Boolean);
  const isIndeterminate = checkedItems.some(Boolean) && !allChecked;

  const { data, isLoading, isFetching, error } = useUsers(page);

  async function handlePrefetchUser(userId: string) {
    await queryClient.prefetchQuery(
      ['user', userId],
      async () => {
        const response = await api.get(`users/${userId}`);

        return response.data;
      },
      {
        staleTime: 1000 * 60 * 10,
      }
    );
  }

  return (
    <Box>
      <Header />

      <Flex my="6" maxWidth={1480} mx="auto" px="6">
        <Sidebar />

        <Box flex="1" borderRadius={8} bg="gray.800" p="8">
          <Flex mb="8" justify="space-between" align="center">
            <Heading size="lg" fontWeight="normal">
              Alunos
              {!isLoading && isFetching && (
                <Spinner size="sm" color="gray.500" ml="4" />
              )}
            </Heading>

            <HStack spacing={4}>
              <NextLink href="/users/create" passHref>
                <Button as="a" size="sm" fontSize="sm" colorScheme="orange">
                  <Icon as={RiAddLine} fontSize="20" />
                </Button>
              </NextLink>

              <NotificationModal />

              <Button
                as="a"
                size="sm"
                fontSize="sm"
                colorScheme="green"
                cursor="pointer"
              >
                <Icon as={CgImport} />
              </Button>
            </HStack>
          </Flex>

          {isLoading ? (
            <Flex justify="center" align="center">
              <Spinner />
            </Flex>
          ) : error ? (
            <Flex justify="center">
              <Text>Falha ao obter dados dos usuários.</Text>
            </Flex>
          ) : (
            <>
              <Table colorScheme="whiteAlpha">
                <Thead>
                  <Tr>
                    <Th px={['4', '4', '6']} color="gray.300" w="8">
                      <Checkbox
                        colorScheme="orange"
                        isChecked={allChecked}
                        isIndeterminate={isIndeterminate}
                        onChange={(e) =>
                          setCheckedItems([e.target.checked, e.target.checked])
                        }
                      />
                    </Th>

                    <Th>Usuários</Th>
                    <Th>Ações</Th>
                    <Th w="8"></Th>
                  </Tr>
                </Thead>

                <Tbody>
                  {data.users.map((user) => (
                    <Tr key={user.id}>
                      <Td px={['4', '4', '6']}>
                        <Checkbox
                          colorScheme="orange"
                          isChecked={checkedItems[0]}
                          onChange={(e) =>
                            setCheckedItems([e.target.checked, checkedItems[1]])
                          }
                        />
                      </Td>

                      <Td>
                        <Box>
                          <Link
                            color="orange.400"
                            onMouseEnter={() => handlePrefetchUser(user.id)}
                          >
                            <Text fontWeight="bold">{user.name}</Text>
                          </Link>
                          <Text fontSize="sm" color="gray.300">
                            {user.email}
                          </Text>
                        </Box>
                      </Td>

                      <Td>
                        <Box cursor="pointer">
                          <HStack spacing={4}>
                            <Text
                              color="orange.400"
                              _hover={{
                                color: 'orange.500',
                              }}
                            >
                              Editar
                            </Text>
                            <Text
                              color="gray.300"
                              _hover={{
                                color: 'gray.500',
                              }}
                            >
                              Excluir
                            </Text>
                          </HStack>
                        </Box>
                      </Td>
                    </Tr>
                  ))}
                </Tbody>
              </Table>

              <Pagination
                totalCountOfRegisters={data.totalCount}
                currentPage={page}
                onPageChange={setPage}
              />
            </>
          )}
        </Box>
      </Flex>
    </Box>
  );
}

jayker
  • 95
  • 1
  • 5
  • Does this answer your question? [Chakra-UI React Select All/Some Checkboxes](https://stackoverflow.com/questions/67013082/chakra-ui-react-select-all-some-checkboxes) – Ri1a Dec 19 '22 at 10:33

1 Answers1

2

Here is a simplified example of how to manage an unknown number of child checkboxes:

https://codesandbox.io/s/stupefied-currying-s3r7dr?file=/src/App.js

For your use case, it might be helpful to also move the checkboxes and checkbox state into a child component that only renders once the users are loaded. That would allow you to set the initial checkbox state with the correct number of users.

Stafford Rose
  • 769
  • 4
  • 9
  • Thanks! The problem is that I'm doing a pagination. That is, following the solution you posted, if you check the second box, it will appear checked on the next page. – jayker Jun 23 '22 at 17:05