skip to Main Content

I have been working on a webapp which can be used to store collections, there is a dashboard page where all the collections the user can see are shown in a table where each row is a collection and the columns are used to show collection name and a delete button.

This is the collecitonRow.tsx file:

"use client";

import React from "react";
import { useSession } from "next-auth/react";

type TableRow = {
  id: string;
  name: string;
};

type Props = {
  row: TableRow;
  className?: string;
};

const DEFAULT_ROW: TableRow = {
  id: "0",
  name: "Collection",
};

const CollectionRow = ({ row = DEFAULT_ROW, className }: Props) => {


  const handleDeleteCollection = async () => {
    console.log(row.id);
  };

  return (
    <tr key={row.id}>
      <td className={className}>
        <div className="flex flex-col">
          <p className="text-sm">{row.name}</p>
        </div>
      </td>
      <td className={className}>
        <button
          onClick={() => (document.getElementById("delete") as any).showModal()}
          className="btn btn-primary btn-sm"
        >
        </button>
        <dialog id="delete" className="modal">
          <div className="modal-box">
            <h3 className="font-bold text-lg">Delete Collection?</h3>
            <div className="modal-action">
              <form method="dialog">
                <button className="btn btn-primary">Close</button>
              </form>
              <button onClick={handleDeleteCollection}>
                Delete
              </button>
            </div>
          </div>
        </dialog>
      </td>
    </tr>
  );
};

export default CollectionRow;

And here’s the page.tsx where this component is used:

import React from "react";

import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth_options";
import CollectionRow from "@/components/collectionRow";
import AddCollection from "@/components/addCollection";

const TABLE_HEAD = [
  "Name",
  "Delete",
];

type TableRow = {
  id: string;
  name: string;
};

export default async function page() {
  
  // Api request to fetch all rows

  const tableRows: TableRow[] = (await res.json()) || [];

  return (
    <div>
      <div className="h-full w-full bg-base-200">
        <div className="px-0 overflow-auto ">
          <table className="mt-2 w-full min-w-max table-auto text-left">
            <thead>
              <tr>
                {TABLE_HEAD.map((head, index) => (
                  <th
                    key={head}
                    className="cursor-pointer border-y border-primary p-4"
                  >
                    <p className="text-sm flex items-center justify-between gap-2">
                      {head} {index !== TABLE_HEAD.length - 1}
                    </p>
                  </th>
                ))}
              </tr>
            </thead>
            <tbody>
              {tableRows.map((row: TableRow, index) => {
                const isLast = index === tableRows.length - 1;
                const classes = isLast ? "p-4" : "p-4 border-b border-primary ";

                return (
                  <CollectionRow key={index} row={row} className={classes} />
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

My problem is that in handleDeleteCollection i log the row.id but for some reason, whatever row the button is from, the id I get is always the one of the first row. I wanted to use that id to delete the row but i just can’t get it.

I tried editing collectionRow.tsx this way:

"use client";

import React from "react";
import { useSession } from "next-auth/react";

type TableRow = {
  id: string;
  name: string;
};

type Props = {
  row: TableRow;
  className?: string;
};

const DEFAULT_ROW: TableRow = {
  id: "0",
  name: "Collection",
};

const CollectionRow = ({ row = DEFAULT_ROW, className }: Props) => {


  const handleDeleteCollection = async (
    e: React.MouseEvent<HTMLButtonElement, MouseEvent>
  ) => {
    console.log(e.target);
  };

  return (
    <tr key={row.id}>
      <td className={className}>
        <div className="flex flex-col">
          <p className="text-sm">{row.name}</p>
        </div>
      </td>
      <td className={className}>
        <button
          onClick={() => (document.getElementById("delete") as any).showModal()}
          className="btn btn-primary btn-sm"
        >
        </button>
        <dialog id="delete" className="modal">
          <div className="modal-box">
            <h3 className="font-bold text-lg">Delete Collection?</h3>
            <div className="modal-action">
              <form method="dialog">
                <button className="btn btn-primary">Close</button>
              </form>
              <button onClick={handleDeleteCollection} id={row.id}>
                Delete
              </button>
            </div>
          </div>
        </dialog>
      </td>
    </tr>
  );
};

export default CollectionRow;

to log all the button information, id included and it is still the first row’s id.

The weird thing is that all the other information (i only put the name to keep the code clean but there are a lot more in my code) is shown correctly, the only one giving problems is the id. I also tried printing it in page.tsx but there it appears to be correct. I have no idea what i’m doing wrong.
Can anyone please help me? Thanks

2

Answers


  1. This is happening because all your buttons are calling the same dialog to open.

    To fix this in your code you should specify a distinct id for each dialog and call the good one each time you click on a button to open it:

    <button
        onClick={() => (document.getElementById(`delete_${row.id}`)).showModal()}
        className="btn btn-primary btn-sm"
    >
    

    and give this specific id to your modal :

    <dialog id={`delete_${row.id}`} className="modal">
    
    Login or Signup to reply.
  2. You are displaying a td element for each one, and you want the modal to open whenever a button is clicked:

    <td className={className}>
      <button
        onClick={() => (document.getElementById("delete") as any).showModal()}
        className="btn btn-primary btn-sm">
      </button>
      <dialog id="delete" className="modal">
        <div className="modal-box">
          <h3 className="font-bold text-lg">Delete Collection?</h3>
          <div className="modal-action">
            <form method="dialog">
              <button className="btn btn-primary">Close</button>
            </form>
            <button onClick={handleDeleteCollection} id={row.id}>
              Delete
            </button>
          </div>
        </div>
      </dialog>
    </td>
    

    The problem here is that your modal, or dialog, rather has the id of delete for ALL of the rows that is mapped. This is not good. The id should be unique in the entire DOM, not just in the component.

    Try to declare the id as such:

    <dialog id={"delete_"+row.id.toString()} className="modal">...</dialog>
    

    And then the button:

    <button onClick={() => (document.getElementById("delete_"+row.id.toString()) as any).showModal()} className="btn btn-primary btn-sm">...</button>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search