reactjsreact-tablereact-table-v7

Click event with React Table 7


This is my Cell data in column:

import { format } from "date-fns";

export const COLUMNS_ALLLOAN = [
   {
      Header: "Id",
      accessor: "id",
      Cell: ({ row }) => Number(row.id) + 1,
   },
   {
      Header: "Account Number",
      accessor: "acNumber",
      Cell: ({ row }) => <>{row.original.acNumber}</>,
   },
   {
      Header: "Account Name",
      accessor: "acName",
   },
   {
      Header: "Loan Type",
      accessor: "acType",
      Cell: ({ row }) => <>{row.original.acType}</>,
   },
   {
      Header: "Opening Date",
      accessor: "acOpen",
      Cell: ({ row }) => <>{row.original.acOpen}</>,
   },
   {
      Header: "Sanction Date",
      accessor: "acSanction",
      Cell: ({ row }) => <>{row.original.acSanction}</>,
   },
   {
      Header: "Expiry Date",
      accessor: "acExpiry",
      Cell: ({ row }) => <>{row.original.acExpiry}</>,
   },
   {
      Header: "Limit",
      accessor: "acLimit",
      Cell: ({ row }) => <>{Number(row.original.acLimit)}</>,
   },
   {
      Header: "Outstanding",
      accessor: "lastDayBalance",
      Cell: ({ row }) => <>{Number(row.original.lastDayBalance)}</>,
   },
   {
      Header: "Overlimit",
      accessor: "overlimit",
      Cell: ({ row }) => <>{Number(row.original.overLimit)}</>,
   },
   {
      Header: "Available",
      accessor: "available",
      Cell: ({ row }) => <>{Number(row.original.availableBalance)}</>,
   },
   {
      Header: "Edit",
      accessor: "edit",
      Cell: ({ row }) => <button className="btn btn-primary">Edit</button>,
   },
   {
      Header: "Delete",
      accessor: "X",
      Cell: ({ row }) => <button className="btn btn-danger">X</button>,
   },
];


This is my page


import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import Footer from "../../components/Footer";
import { useMemo } from "react";
import { useTable, useSortBy, useGlobalFilter, usePagination } from "react-table";
import { COLUMNS_ALLLOAN } from "../../components/COLUMNS_ALLLOAN.js";
import Globalfilter from "../../components/Globalfilter";
import { deleteById, getLoans } from "../../features/bradvance/advanceSlice";

const Allloans = () => {
   const dispatch = useDispatch();

   const { allLoans } = useSelector((state) => state.bradvance);

   const navigate = useNavigate();

   const goBack = async () => {
      navigate(-1);
   };

   const columns = useMemo(() => COLUMNS_ALLLOAN, []);
   const data = useMemo(() => allLoans, []);

   // console.log(data);

   const tableInstance = useTable(
      {
         columns,
         data: allLoans,
         initialState: { pageSize: 30 },
      },

      useGlobalFilter,
      useSortBy,
      usePagination
   );

   const {
      headerGroups,
      getTableProps,
      getTableBodyProps,
      page,
      prepareRow,
      state,
      setGlobalFilter,
      nextPage,
      previousPage,
      canNextPage,
      canPreviousPage,
      pageOptions,
      setPageSize,
      gotoPage,
      pageCount,
   } = tableInstance;

   const { globalFilter, pageIndex, pageSize } = state;

   // console.log(data.length);

   const totalLoan = allLoans
      .map((item, sl) => {
         return item.lastDayBalance;
      })
      .reduce((acc, curValue) => {
         // console.log(curValue);
         return acc + curValue;
      }, 0);

   // console.log(totalLoan);
   const handleClick = (id) => {
      dispatch(deleteById(id));
      alert("Deleted Successfully.");
      console.log(id);
   };

   return (
      <>
         <div className="container">
            <div className="row">
               <div className="col">
                  <div className="summary">
                     <h1 className="p-4 text-center fw-bold mb-0">All Loans</h1>
                  </div>
               </div>
            </div>
            <div className="row">
               <div className="col">
                  <Globalfilter filter={globalFilter} setFilter={setGlobalFilter} />
               </div>
            </div>
            <div className="row">
               <div className="col">
                  <div className="summary  table-responsive">
                     <table {...getTableProps()} className="table table-hover table-bordered">
                        <thead>
                           {headerGroups.map((headerGroup) => (
                              <tr {...headerGroup.getHeaderGroupProps()}>
                                 {headerGroup.headers.map((column) => (
                                    <th {...column.getHeaderProps(column.getSortByToggleProps())}>{column.render("Header")} </th>
                                 ))}
                              </tr>
                           ))}
                        </thead>
                        <tbody {...getTableBodyProps()}>
                           {page.map((row, i) => {
                              prepareRow(row);
                              return (
                                 <tr {...row.getRowProps()}>
                                    {row.cells.map((cell) => {
                                       return (
                                          <td onClick={() => handleClick(row.original.id)} {...cell.getCellProps()}>
                                             {cell.render("Cell")}
                                          </td>
                                       );
                                    })}
                                 </tr>
                              );
                           })}
                        </tbody>
                     </table>
                  </div>
               </div>
            </div>
            <div className="row ">
               <div className="col d-flex justify-content-end">
                  <ul className="list-group list-group-horizontal">
                     <li className="list-group-item fw-bold">
                        Total Loan: <span className="fw-bold text-danger">{allLoans.length}</span>
                     </li>
                     <li className="list-group-item fw-bold">
                        Total Amount:<span className="fw-bold text-danger">{totalLoan.toFixed(2)}</span>{" "}
                     </li>
                  </ul>
               </div>
            </div>

            <div className="section p-5 pagination col-12">
               <button className="page-link" onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
                  {"<<"}
               </button>{" "}
               <button className="page-link" onClick={() => previousPage()} disabled={!canPreviousPage}>
                  {"<"}
               </button>{" "}
               <button className="page-link" onClick={() => nextPage()} disabled={!canNextPage}>
                  {">"}
               </button>{" "}
               <button className="page-link" onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
                  {">>"}
               </button>{" "}
               <span className="page-link">
                  Page{" "}
                  <strong>
                     {pageIndex + 1} of {pageOptions.length}
                  </strong>{" "}
               </span>
               <span className="page-link">
                  | Go to page:{" "}
                  <input
                     type="number"
                     value={pageIndex + 1}
                     onChange={(e) => {
                        const page = e.target.value ? Number(e.target.value) - 1 : 0;
                        gotoPage(page);
                     }}
                     style={{ width: "100px" }}
                  />
               </span>{" "}
               <select
                  className="page-link"
                  value={pageSize}
                  onChange={(e) => {
                     setPageSize(Number(e.target.value));
                  }}
               >
                  {[20, 50, 100, 200, 500].map((pageSize) => (
                     <option key={pageSize} value={pageSize} className="page-link">
                        Show {pageSize}
                     </option>
                  ))}
               </select>
            </div>

            {/* Go Back */}
            <div className="row ">
               <div className="col ">
                  <div className="text-center summary pb-3">
                     <button className="btn btn-outline-primary mb-0" onClick={goBack}>
                        <i className="bi bi-skip-backward"></i> Go Back
                     </button>
                  </div>
               </div>
            </div>
            <div className="row">
               <div className="col">
                  <Footer />
               </div>
            </div>
         </div>
      </>
   );
};

export default Allloans;


This is how my page looks:

enter image description here

I can delete each row successfully. The problem is that it deletes when I click on any part of the row. But, I want only the button to be clickable not the whole row. I mean, when I click the delete button only, it should delete.


Solution

  • First, remove the onClick={() => handleClick(row.original.id)} from your row td tag so it become as follows

    {row.cells.map((cell) => {
      return (
        <td {...cell.getCellProps()}>
            {cell.render("Cell")}
        </td>
      );
    })}
    

    next, move your on-click handler to the top of the table instance creation

    ...
      const handleClick = (id) => {
        dispatch(deleteById(id));
        alert("Deleted Successfully.");
        console.log(id);
      };
    
      const tableInstance = useTable(
        {
             ...
        }
      );
    

    then, remove the last two columns' definitions (Edit & Delete def) from COLUMNS_ALLLOAN and insert those col definitions into useTable and finally add the onClick event listener to the delete button.

      const tableInstance = useTable(
        {
          columns,
          data: allLoans,
          initialState: { pageSize: 30 },
        },
        useGlobalFilter,
        useSortBy,
        usePagination,
        // create Edit and Delete col definition by pushing the two into visibleColumns
        (hooks) => {
          hooks.visibleColumns.push((col) => [
            ...col,
            {
              Header: "Edit",
              id: "editBtn",
              Cell: ({ row }) => <button className="btn btn-primary">Edit</button>,
            },
            {
              Header: "Delete",
              id: "deleteBtn",
              Cell: ({ row }) => <button onClick={() => handleClick(row.original.id)} className="btn btn-danger">X</button>,
            },
          ]);
        }
      );
    

    Here is the minimal example:

    Edit staging-fast-i17idb