Tanu
Tanu

Reputation: 1640

How to make collapsible work only for the row clicked

I want to make the row icon I click collapsible and display data. Presently if any of the row in table is clicked, it displays the collapsible content for all the rows.

              {data.map((dataRow) => (
                <TableRow
                  key={dataRow.id}
                  title="tableRow"
                  className={classes.tableRow}
                >
                  <TableCell className={classes.tableCell}>
                    <IconButton size="small" onClick={() => setOpen(!open)}>
                      {open ? <ArrowDropDownIcon /> : <ArrowDropUpIcon />}
                    </IconButton>
                    {dataRow.id}
                    <Collapse in={open} timeout="auto" unmountOnExit>
                      <Box margin={1}>
                        <Typography variant="h6" gutterBottom component="div">
                          History
                        </Typography>
                      </Box>
                    </Collapse>
                  </TableCell>
                  <TableCell className={classes.tableCell}>
                    {dataRow.name}
                  </TableCell>
                  <TableCell align="left" className={classes.tableCell}>
                    {dataRow.lastName}
                  </TableCell>
                </TableRow>
              ))}
            </TableBody>

Upvotes: 1

Views: 431

Answers (3)

Tanu
Tanu

Reputation: 1640

This does not work. Any suggestions on what could be the error here : Thanks

  const [openRows, setOpenRows] = useState<Record<string, boolean>>({});

  const toggleRow = (dataRow: any) =>
    setOpenRows((prevState) => ({
      ...prevState,
      [dataRow.overrideTicketNumber]: true,
    }));
                  <IconButton
                    size="small"
                    onClick={() => toggleRow(dataRow.overrideTicketNumber)}
                  >
                    {openRows ? <ArrowDropDownIcon /> : <ArrowDropUpIcon />}
                  </IconButton>
                  <Collapse
                    in={openRows[dataRow.overrideTicketNumber] ?? false}
                    timeout="auto"
                    unmountOnExit
                  >
                    <Box margin={1}>
                      <Typography variant="h6" gutterBottom component="div">
                        {dataRow.overrideTicketNumber}
                      </Typography>
                    </Box>
                  </Collapse>
                </TableCell>

Upvotes: 0

Steffen Frank
Steffen Frank

Reputation: 1797

You can change the state variable open from a boolean value to an object that keeps track of the open/closed state of all rows:

const [openRows, setOpenRows] = useState({});

const toggleRow = (rowId) =>
  setOpenRows((previous) => ({
    ...previous,
    [rowId]: !(previous[rowId] ?? false),
  }));

return (
  <TableBody>
    {data.map((dataRow) => (
      <TableRow key={dataRow.id} title="tableRow" className={classes.tableRow}>
        <TableCell className={classes.tableCell}>
          <IconButton size="small" onClick={() => toggleRow(dataRow.id)}>
            {open ? <ArrowDropDownIcon /> : <ArrowDropUpIcon />}
          </IconButton>
          {dataRow.id}
          <Collapse in={openRows[dataRow.id] ?? false} timeout="auto" unmountOnExit>
            <Box margin={1}>
              <Typography variant="h6" gutterBottom component="div">
                History
              </Typography>
            </Box>
          </Collapse>
        </TableCell>
        <TableCell className={classes.tableCell}>{dataRow.name}</TableCell>
        <TableCell align="left" className={classes.tableCell}>
          {dataRow.lastName}
        </TableCell>
      </TableRow>
    ))}
  </TableBody>
);

Upvotes: 0

Marat
Marat

Reputation: 629

You have one state variable "open" that is used in every row to determine if it is collapsed or not. So, all the rows are collapsed or all of them are open.

To open them one by one you need a separate state variable for each of the rows. You can create something like this:

const [openRows, setOpenRows] = useState({});

the keys in this object will be dataRow.id, and the values - boolean

So, when you need to open a specific row you call setOpenRows like this:

setOpenRows((prevState) => {
  return { ...prevState, [dataRow.id]: true }
});

or with [dataRow.id]: false when you need to close it

And you pass the new value to Collapse component

<Collapse in={openRows[dataRow.id]} timeout="auto" unmountOnExit>

Upvotes: 1

Related Questions