I am trying to build a CRUD app using react and tanstack table v8 within sharepoint framework using React as the framework. I am running into an issue outlined below.
I have to do an API call to sharepoint to get the Digest Key so I can write to the list. This works and I pass that down to the table component code file below. I can see in my console that both the parent component and table component do have the value of the key when the web part loads.
The issue I am running into is when I pass requestDigest into the onClick of the buttons in the columnDef object array the console shows it as empty. I have another component file for a form that writes to the list that they key shows fine and the POST works. So I am guessing it is some sort of scope issue but I am at a loss as I have even tried making the buttons components and passing the components into columnDef but that did not work either.
Code for table component below
import React, {useState, useEffect} from "react";
import "./table.css";
import {
useReactTable,
flexRender,
getCoreRowModel,
createColumnHelper
} from "@tanstack/react-table";
//import { columnDef } from "./columns";
import dataJSON from "./data.json";
import SharePointForm from "./SubmitForm";
const sharepoint_url = '[redacted]/_api/web/lists/getbytitle(\'TanStackTableData\')/items';
const BasicTable = ({requestDigest}) => {
console.log(requestDigest, "FROM TABLE COMPONENT") // This shows in my console
const updateData = async (id, requestDigest) => {
console.log("Update Key:", requestDigest);
const data = {
__metadata: { type: 'SP.Data.TanStackTableDataListItem' },
Title: SharePointForm.firstName,
first_name: SharePointForm.firstName,
last_name: SharePointForm.lastName,
};
fetch(`[redacted]/_api/web/lists/getbytitle(\'TanStackTableData\')/items(${id})`, {
method: 'POST',
headers: {
"Accept": "application/json;odata=verbose",
"Content-Type": "application/json;odata=verbose",
"If-Match": "*",
"X-HTTP-Method": "MERGE",
"X-RequestDigest": requestDigest
},
body: JSON.stringify(data)
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok.');
}
return response.json();
})
.then(data => {
fetchData();
console.log('Data successfully added:', data);
setFirstName('');
setLastName('')
// Optionally, update state or perform actions on successful addition of data
})
.catch(error => {
console.error('Error adding data:', error);
// Handle error scenario
});
};
const columnDef = [
{
accessorKey: 'ID',
header: 'ID'
},
{
accessorKey: 'first_name',
header: 'First Name'
},
{
accessorKey: 'last_name',
header: 'Last Name'
},
{
header: "Actions",
accessorKey: "ID",
cell: (cell) => {
return (
<>
<button onClick={() => handleButtonClick(cell.row.original?.ID, setFirstNameUpdate, setLastNameUpdate, requestDigest)}>Edit</button>
<button onClick={() => updateData(cell.row.original?.ID, requestDigest)}>Update</button>
</>
);
}
}
]
const columnHelper = createColumnHelper();
const [firstNameUpdate, setFirstNameUpdate] = useState('');
const [lastNameUpdate, setLastNameUpdate] = useState('');
const fetchUpdateDataFromSharePoint = async (id) => {
console.log(requestDigest, "Initial Data Grab")
try {
const response = await fetch(`[redacted]/_api/web/lists/getbytitle(\'TanStackTableData\')/items(${id})`, {
method: 'GET',
headers: {
// Include headers as needed for authentication
'Accept': 'application/json;odata=verbose',
'Content-Type': 'application/json',
},
});
const data = await response.json();
return data;
} catch (error) {
console.error('Error fetching data:', error);
throw error;
}
};
const handleButtonClick = async (ID, setFirstNameUpdate, setLastNameUpdate, requestDigest) => {
// Handle button click event here, using data from the row if needed
console.log('Button clicked for row:', ID);
// Perform your desired action...
try {
// Fetch data from SharePoint based on the ID
const data = await fetchUpdateDataFromSharePoint(ID);
console.log(data)
setFirstNameUpdate(data.d.first_name);
setLastNameUpdate(data.d.last_name);
console.log("From grab update data", requestDigest);
} catch (error) {
console.error('Error handling button click:', error);
}
};
const fetchData = async () => {
try {
// Fetch data from SharePoint list
const response = await fetch(sharepoint_url, {
method: 'GET',
headers: {
// Include headers as needed for authentication
'Accept': 'application/json;odata=verbose',
'Content-Type': 'application/json',
},
});
if (response.ok) {
const result = await response.json();
setListData(result.d.results);
} else {
// Handle error responses
console.error('Failed to fetch data:', response.statusText);
}
} catch (error) {
console.error('Error fetching data:', error);
}
};
useEffect(() => {
fetchData();
}, []);
const [listData, setListData] = useState([])
const [columnDefFinal, setColumnDefFinal] = useState(columnDef)
//let listData = [];
console.log(listData);
// const finalData = React.useMemo(() => listData, []);
// console.log('final', finalData);
// const finalColumnDef = React.useMemo(() => columnDef, []);
const tableInstance = useReactTable({
columns: columnDefFinal,
data: listData,
getCoreRowModel: getCoreRowModel(),
});
console.log("hello");
console.log("test", tableInstance.getHeaderGroups());
return (
<>
<table>
<thead>
{tableInstance.getHeaderGroups().map((headerEl) => {
return (
<tr key={headerEl.id}>
{headerEl.headers.map((columnEl) => {
return (
<th key={columnEl.id} colSpan={columnEl.colSpan}>
{columnEl.isPlaceholder
? null
: flexRender(
columnEl.column.columnDef.header,
columnEl.getContext()
)}
</th>
);
})}
</tr>
);
})}
</thead>
<tbody>
{tableInstance.getRowModel().rows.map((rowEl) => {
return (
<tr key={rowEl.id}>
{rowEl.getVisibleCells().map((cellEl) => {
return (
<td key={cellEl.id}>
{flexRender(
cellEl.column.columnDef.cell,
cellEl.getContext()
)}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
<SharePointForm fetchData={fetchData} firstNameUpdate={firstNameUpdate} lastNameUpdate={lastNameUpdate} requestDigest={requestDigest} />
</>
);
};
export default BasicTable;