0

I am using the custom function option for downloading a CSV usingMaterialTable. In the function I am modifying the data of only three columns.

When exportCsv is executed then the data array will contain the last changes which will results on a wrong output.

const downloadCsv = (data, fileName) => {
  const finalFileName = `${fileName}.csv`;
  const a = document.createElement("a");
  a.href = URL.createObjectURL(new Blob([data], { type: "text/csv" }));
  a.setAttribute("download", finalFileName);
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
}

export default function ReTable(props) {

 const resultsData = useSelector((state) => state.results.data);
 return (
    <div>
        <MaterialTable
            columns={columns}
            data={resultsData}
            options={{
            ........
            .......
            .....

    exportCsv: (columns, data) => {
       const csvData = [...resultsData];
       csvData.forEach(item => {
            item.account = '="' + item.account + '"';
            item.zip4 = '="' + item.zip4 + '"';
            item.zip5 = '="' + item.zip5 + '"';
      });
      
      const dataRows = csvData.map(({ tableData, ...row }) => Object.values(row));
      const csvContent = [header, ...dataRows].map(e => e.join(',')).join("\n");
      downloadCsv(csvContent, props.name);
 },

I don’t want to change the data so I have created a new csvData but apparently its it is effecting the data.

I am not sure what I am doing wrong ? I need to update the columns only ones.

Thank you

angus
  • 3,210
  • 10
  • 41
  • 71
  • The problem isn't that the array is immutable or not, the real issue is that `const csvData = [...resultsData];` only does a shallow copy of the data. So you get a *new array*, but all the objects in it are shared with the old array. You need to do a deep clone of the array and each object. – VLAZ Nov 30 '20 at 15:49
  • Does this answer your question? [How do you clone an Array of Objects in Javascript?](https://stackoverflow.com/questions/597588/how-do-you-clone-an-array-of-objects-in-javascript) – Heretic Monkey Nov 30 '20 at 16:03

1 Answers1

2

You're just doing a shallow copy of the array when you call [...resultsData]. Either use a library that will do a deep copy, find one of the many SO answers that will provide a solution, or do the work of converting values when you call map instead of worrying about making the array immutable:

exportCsv: (columns, data) => {
  const colsToTransform = ['account', 'zip4', 'zip5'];
  const dataRows = resultsData.map(x => Object.entries(x)
    .map(kvp => (colsToTransform.includes(kvp[0])) ? '="' + kvp[1] + '"' : kvp[1]));
  const csvContent = [header, ...dataRows].map(e => e.join(',')).join("\n");
  downloadCsv(csvContent, props.name);
}
Daniel Gimenez
  • 18,530
  • 3
  • 50
  • 70