Below is the code I am using for generating a table.
I need to make each row clickable and navigate to different page. How to do that?
import { useMemo, useState, useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { DataGrid, KeenIcon, TDataGridRequestParams } from '@/components';
import { ColumnDef } from '@tanstack/react-table';
import axios from 'axios';
import { FetchLicensesResponse, LicenseModel } from '@/providers';
import { enqueueSnackbar } from 'notistack';
import { Container } from '@/components/container';
import { LicenseViewModal } from './LicenseViewModal';
const LicenseTable = () => {
const navigate = useNavigate();
const location = useLocation();
const [viewLicenseModal, setViewLicenseModal] = useState(false);
const [selectedLicenseId, setSelectedLicenseId] = useState("");
useEffect(() => {
const queryParams = new URLSearchParams(location.search);
const licenseId = queryParams.get('licenseId');
const modalOpen = queryParams.get('modal') === 'true';
if (modalOpen && licenseId) {
setSelectedLicenseId(licenseId);
setViewLicenseModal(true);
}
}, [location.search]);
const handleSettingsModalClose = () => {
setViewLicenseModal(false);
navigate(location.pathname);
};
const handleLicenseViewAction = (licenseId: string) => {
navigate(`/license/${licenseId}`)
// navigate(`?modal=true&licenseId=${licenseId}`);
};
const columns = useMemo<ColumnDef<LicenseModel>[]>(
() => [
{
accessorFn: (row) => row,
id: 'licenseName',
header: () => 'Name',
cell: (info) => info.row.original.LicenseName,
meta: { headerClassName: 'min-w-[180px]' },
},
{
accessorFn: (row) => row,
id: 'licenseType',
header: () => <div className='text-center'>Type</div>,
cell: (info) => <div className='text-center'>{info.row.original.LicenseType}</div>,
meta: { headerClassName: 'min-w-20' },
},
{
accessorFn: (row) => row,
id: 'organisation',
header: () => 'Organisation',
cell: (info) =>
info.row.original.Organisation || <div>---</div>,
meta: { headerClassName: 'min-w-[180px]' },
},
{
accessorFn: (row) => row,
id: 'unit',
header: () => 'Unit',
cell: (info) =>
info.row.original.Unit || <div>---</div>,
meta: { headerClassName: 'min-w-[180px]' },
},
{
accessorFn: (row) => row,
id: 'revoked',
header: () => <div className='text-center'>Revoked</div>,
cell: (info) =>
<div className='text-center'>
<span className={`badge badge-sm ${info.row.original.Revoked ? 'badge-danger' : 'badge-success'} badge-outline`}>
{info.row.original.Revoked ? <KeenIcon icon="check" /> : <KeenIcon icon="cross" />}
</span>
</div>,
meta: { headerClassName: 'min-w-10 text-center' },
},
{
accessorFn: (row) => row,
id: 'action',
header: () => <div className='text-center'>Action</div>,
cell: (info) => (
<div className="flex flex-wrap gap-5 justify-center">
<div className="flex">
<button
className="btn btn-sm btn-primary btn-outline"
data-toggle="tooltip"
title="View details"
onClick={() => handleLicenseViewAction(info.row.original.LicenseId)}
>
<KeenIcon icon="eye" />
</button>
</div>
<div className="flex">
<button
className="btn btn-sm btn-danger btn-outline"
data-toggle="tooltip"
title="Deactivate"
>
<KeenIcon icon="shield-slash" />
</button>
</div>
</div>
),
meta: { headerClassName: 'min-w-5 text-center' },
},
],
[]
);
const onFetchData = async (params: TDataGridRequestParams) => {
try {
const offset = params.pageIndex * params.pageSize;
const response = await axios.post<FetchLicensesResponse>(
`${import.meta.env.VITE_APP_API_URL}/license/fetch`,
{ maxEntries: params.pageSize, offset }
);
return {
data: response.data.licenses || [],
totalCount: 30,
offset,
nextOffset: offset + params.pageSize,
};
} catch (error) {
console.error('Failed to fetch data:', error);
enqueueSnackbar('An error occurred while fetching data. Please try again later', {
variant: 'solid',
state: 'danger',
});
return {
data: [],
totalCount: 0,
offset: 0,
};
}
};
return (
<>
<div className="card card-grid min-w-full">
<div className="card-header flex-wrap gap-2">
<h3 className="card-title font-medium text-sm">Your Licenses
</div>
<div className="card-body">
<DataGrid
layout={{ card: true, cellBorder: false }}
columns={columns}
serverSide={true}
onFetchData={onFetchData}
rowSelection={false}
pagination={{ size: 10 }}
/>
</div>
</div>
<Container>
<LicenseViewModal
open={viewLicenseModal}
onOpenChange={handleSettingsModalClose}
licenseId={selectedLicenseId}
/>
</Container>
</>
);
};
export { LicenseTable };
I would like to make entire row clickable and not just one cell. Yes, will use router link to navigate to internal page.
Hi,
We will add this option in the next update.
You can implement it now by modifying src/components/data-grid/DataGrid.tsx
and add onRowClick prop.
export interface TDataGridProps<TData extends object> {
onRowClick?: (row: TData) => void;
}
src/components/data-grid/DataGridTable.tsx
add the row click handle:{table.getRowModel().rows.length ? (
table.getRowModel().rows.map((row: Row<TData>) => (
<tr
key={row.id}
data-state={row.getIsSelected() ? "selected" : undefined}
onClick={() => props.onRowClick && props.onRowClick(row.original)}
className={cn(
"border-b hover:bg-muted/30 data-[state=selected]:bg-muted/50",
cellBorder && "[&_>:last-child]:border-e-0"
)}
>
...
</tr>
))
Hi,
Could you please confirm if you want to make an entire row click or a button click inside a cell of a row to navigate to a new page? Will you use the Router link to navigate to an internal page?
You can try to use this in the columns config:
cell: (info) => (
<div
className="cursor-pointer hover:bg-gray-100"
onClick={() => navigate(`/license/${info.row.original.LicenseId}`)}
>
{info.row.original.LicenseName}
</div>
)