Material-table: Some fields are not exported in the CSV

Created on 4 May 2019  路  10Comments  路  Source: mbrn/material-table

Describe the bug
Fields are missing in the exported CSV.

I've just noticed that fields with custom value are not exported in the CSV. See code below that concatenates the year and month.

                columns={[
                  {
                    title: 'Date', headerStyle: {minWidth: '20px', maxWidth: '20px'},
                  cellStyle: data => { return { paddingRight: 4, paddingLeft: 5,minWidth: '20px', maxWidth: '20px' }},   
                    render: rowData => rowData.year + '-' + rowData.month + '-' + rowData.day
                  },
                  {
                    title: 'P/L%', headerStyle: {paddingRight: 4, paddingLeft: 5,minWidth: '35px', maxWidth: '35px'},
                    cellStyle: data => { return { paddingRight: 4, paddingLeft: 5,minWidth: '35px', maxWidth: '35px' }}, 
                    field: 'profit_percent', type: 'numeric',         
                    render: rowData => {
                      var profit_percent = parseFloat(rowData.profit)/parseFloat(rowData.investment) * 100
                      var profit = parseFloat(profit_percent).toFixed(2) + '%'
                      var bgcolor;
                      var fontColor = 'black';
                      if (profit_percent < 0) {
                        bgcolor = '#b71c1c';
                        fontColor = 'white';
                      }
                      else if (profit_percent > 0) {
                        bgcolor = '#4caf50';
                        fontColor = 'white';
                      }
                      return (
                        <div
                          style={{
                            float: 'right',
                            padding: 1,
                            color: fontColor,
                            maxWidth: 50,
                            backgroundColor: bgcolor,
                            height: 20,
                          }}
                        >
                          {profit}
                        </div>
                      )
                    }
                  },
                  {
                    title: 'P/L', field: 'revenue', type: 'numeric', headerStyle: {paddingRight: 4, paddingLeft: 5,minWidth: '100px', maxWidth: '100px' },
                    cellStyle: data => { return { paddingRight: 4, paddingLeft: 5,minWidth: '100px', maxWidth: '100px'  } },
                    render: rowData => rowData.profit.toFixed(8)
                  },
                  {
                    title: 'Investment', type: 'numeric', headerStyle: {paddingRight: 4, paddingLeft: 5, minWidth: '100px', maxWidth: '100px' },
                    cellStyle: data => { return {paddingRight: 4, paddingLeft: 5,minWidth: '100px', maxWidth: '100px'} },
                    render: rowData => parseFloat(rowData.investment).toFixed(8)
                  },
                  {
                    title: 'Revenue', field: 'revenue', type: 'numeric',  headerStyle: {paddingRight: 4, paddingLeft: 5, minWidth: '100px', maxWidth: '100px' },
                    cellStyle: data => { return {paddingRight: 4, paddingLeft: 5,minWidth: '100px', maxWidth: '100px'} },
                    render: rowData => parseFloat(rowData.revenue).toFixed(8)
                  },
                  {
                    title: 'Commission', field: 'base_commission', type: 'numeric',  headerStyle: {paddingRight: 4, paddingLeft: 5, minWidth: '100px', maxWidth: '100px' },
                    cellStyle: data => { return {paddingRight: 4, paddingLeft: 5,minWidth: '100px', maxWidth: '100px'} },
                    render: rowData => parseFloat(rowData.base_commission).toFixed(8)
                  },                  
                  {
                    title: 'Cummulative Profit', field: 'cummulative_profit', type: 'numeric', headerStyle: {paddingRight: 4, paddingLeft: 5,minWidth: '100px', maxWidth: '100px'},
                    cellStyle: data => { return {paddingRight: 4, paddingLeft: 5,minWidth: '100px', maxWidth: '100px'} },
                    render: rowData => parseFloat(rowData.cummulative_profit).toFixed(8)
                  },
                  {
                    title: 'Won', field: 'won', type: 'numeric', headerStyle: { maxWidth: '20px' },
                    cellStyle: data => { return { maxWidth: '20px' } },
                  },
                  {
                    title: 'Lost', field: 'lost', type: 'numeric', headerStyle: { maxWidth: '20px' },
                    cellStyle: data => { return { maxWidth: '20px' } },
                  },
                  {
                    title: 'Avg Holding Time', headerStyle: { paddingRight: 4, paddingLeft: 5,minWidth: '80px'},
                    cellStyle: data => { return {paddingRight: 4, paddingLeft: 5,minWidth: '80px'} },
                    render: rowData => formatDistance(Date.now(),Date.now() - rowData.total_hold_time/rowData.tran_count),
                  }

To Reproduce
Steps to reproduce the behavior:

  1. In the table, click the Export to CSV.

Expected behavior
The CSV should contain the custom field.

Screenshots
Table
image

CSV
It is missing the Date, P/L% (no value), Investment, Average Holding Time.
Daily Sales.xlsx

help wanted wontfix

Most helpful comment

Hi,
I got around this issue by using a custom export function that uses the render method for the column.
This way the data exported matches the data in the table exactly.

const exportCsv = (columnList, initialData) => {
  const columns = columnList.filter(columnDef => {
    return !columnDef.hidden && columnDef.field && columnDef.export !== false;
  });

  const data = initialData.map(rowData =>
    columns.map(columnDef => {
      return columnDef.render ? columnDef.render(rowData) : rowData[columnDef.field];
    })
  );

  const builder = new CsvBuilder('data' + '.csv');
  builder
    .setDelimeter(',')
    .setColumns(columns.map(columnDef => columnDef.title))
    .addRows(data)
    .exportFile();
};

All 10 comments

Hi,
I got around this issue by using a custom export function that uses the render method for the column.
This way the data exported matches the data in the table exactly.

const exportCsv = (columnList, initialData) => {
  const columns = columnList.filter(columnDef => {
    return !columnDef.hidden && columnDef.field && columnDef.export !== false;
  });

  const data = initialData.map(rowData =>
    columns.map(columnDef => {
      return columnDef.render ? columnDef.render(rowData) : rowData[columnDef.field];
    })
  );

  const builder = new CsvBuilder('data' + '.csv');
  builder
    .setDelimeter(',')
    .setColumns(columns.map(columnDef => columnDef.title))
    .addRows(data)
    .exportFile();
};

@Foosballfan Created a PR based off of your solution, also added example to the demo page.

There is one issue with my solution, which is also discussed in my open PR.
The render() function is able to return non primitive values (such as JSX elements).

The change that @mbrn seemed to suggest (still waiting to hear back from him)is to use the 'type' parameter on the render function.

That way when configuring your columns, if you use a render function then you should accept the parameter 'group' and return a primitive value in that case.

If that is what mbrn wants for my PR then it would make sense for this case too.

@Foosballfan going through the comments on your PR, I think a displayValueAccessor might be the best way to go. I don't think it adds any bloat as such either, react-big-calendar uses accessors for almost all props and it gives a lot of flexibility

Yeah, I did mention it here https://github.com/mbrn/material-table/pull/530#discussion_r280312890 but it didn't really get acknowledged. I've also since lost all communication with @mbrn. Maybe you would stand a better chance fo getting a reply from him.

Well. I have emailed him a while ago, let's see how that goes.

Hi @theamanbhargava ,

I saw you prs. I will check them and merge asap. You may know, this is the Ramadan for muslims and i am very busy nowadays. Thanks for your patience.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. You can reopen it if it required.

Hi,
I am also facing similar kind of issue in export to csv. Below is my columns which for some are having custom render. When I export to csv, the data for the columns which is having custom render (specially ) is coming [object object] in the exported csv file

Can any one help me in fixing this issue.

  columns: [
    {
      title: 'Invoice Number',
      field: 'ivcCd',
      editable: 'never',
      name: 'ivcCd',
      type: 'text',
      render: rowData =>
        rowData.ast != '' ? (
          <span>
            {rowData.ivcCd} <span style={{ fontSize: 16, color: '#106ebe' }}>{rowData.ast}</span>
          </span>
        ) : (
          rowData.ivcCd
        ),
    },
    {
      title: 'Invoice Type',
      field: 'invType',
      editable: 'never',
      render: rowData =>
        rowData.invType == 'MER'
          ? 'Merchandise'
          : rowData.invType == 'EXP'
            ? 'Expense'
            : rowData.invType == 'DBM'
              ? 'Debit Memo'
              : rowData.invtype,
    },
    {
      title: 'Vendor ID',
      field: 'veCd',
      editable: 'never',
    },
    {
      title: 'Vendor Name',
      field: 'veName',
      editable: 'never',
    },
    {
      title: '',
      field: 'ast',
      editable: 'never',
      width: '40px',
      hidden: true,
      export: true,
    },
    {
      title: 'Post Date',
      field: 'postDate',
      type: 'date',
      editable: 'never',
      editComponent: props => <DatePicker type="date" value={props.value || null} onChange={event => props.onChange(event.target.value)} />,
    },
    {
      title: 'Payment Due Date',
      field: 'payDueDate',
      type: 'date',
      editable: 'never',
      editComponent: props => <DatePicker type="date" value={props.value || null} onChange={event => props.onChange(event.target.value)} />,
    },
    {
      title: 'Payment Due',
      field: 'paymentDue',
      editable: 'never',
      type: 'numeric',
    },
    {
      title: 'Balance Due',
      field: 'balanceDue',
      editable: 'never',
      type: 'numeric',
    },
    {
      title: 'Disburse Amount',
      field: 'cdisAmt',
      type: 'numeric',
    },
  ],

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. You can reopen it if it required.

Was this page helpful?
0 / 5 - 0 ratings