Skip to content
Advertisement

How can I implement a table with nested dropdown items?

I’m trying to make a table like this:

| --------  
| - <Tr> 
|  + <Tr>
|  - <Tr> 
|   - <Tr> 
|    - <Tr>
|      <Tr>
|      <Tr>
|      <Tr>
| + <Tr> 
| + <Tr> 

Table elements can contain thousands of child dropdown elements.
I am writing code in React and so far I have no idea and have not figured out how it can be done in a more optimized way.
Right now I am trying to work with a data structure like this

[
  {
    id: 1,
    childrens: [
      { id: 10, childrens: [] },
      { id: 11, childrens: [{ id: 12, childrens: [] }] },
    ],
  },
  { id: 2, childrens: [] },
];

Current implementation idea:
When I click on the dropdown element, I do the following:

  1. Get id
  2. I am looking for an element in the array by id
  3. I get the contents of childrens, if the array contains data, then I add them after the parent <tr> element

To hide the dropdown <tr> I do the following:

  1. Get id
  2. I am looking for an element in the array by id
  3. Get the length of the array childrens
  4. I delete after the parent <tr element, the number of child <tr is equal to the length of the array

But I don’t understand how I can work with nested child elements. I need to somehow understand who is the parent of whom in order not to bypass the entire array again.

In what direction should I explore this issue?

Advertisement

Answer

I had to do this once and solved it using recursion. Create your table and loop over the first layer of data.

const TableDropdown = ({ data }) => {
  return (
    <table>
      <tbody>
        // loop over the first layer of data
        {data.map((row) => (
          <DropdownRow key={`dropdown-row-${row.id}`} row={row} />
        ))}
      </tbody>
    </table>
  );
};

For the implementation of the row

  1. In the row we set a state to keep track of the open state.
  2. Define a toggle function to toggle between open and closed.
  3. Finally determine whether or not we have children and check if the dropdown is open.
const DropdownRow = ({ row }) => {
  const [isOpen, setIsOpen] = useState(false);
  // check whether the row has children
  const hasChildren = row.childrens.length > 0;

  // toggle the row
  const toggleRow = () => {
    // no need to toggle if no children
    if (!hasChildren) return;
    setIsOpen((prev) => !prev);
  };

  // create the child rows if the current row has children and is opened
  const childRows =
    hasChildren && isOpen
      ? row.childrens.map((childRow) => (
          <DropdownRow key={`dropdown-row-${childRow.id}`} row={childRow} />
        ))
      : null;

  // just to determine which "icon" to display
  const toggleIcon = !hasChildren ? "=" : isOpen ? "-" : "+";

  return (
    <>
      <tr>
        <td onClick={toggleRow}>{toggleIcon}</td>
        <td>Row with id {row.id}</td>
      </tr>
      {childRows}
    </>
  );
};

Check here for a live version

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement