Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[QUESTION] How to get sum of column values in footer. #101

Closed
vinodkhandelwal opened this issue Feb 28, 2017 · 19 comments
Closed

[QUESTION] How to get sum of column values in footer. #101

vinodkhandelwal opened this issue Feb 28, 2017 · 19 comments

Comments

@vinodkhandelwal
Copy link

I need to sum the column values and show that in footer. Footer Demo seems to have missing the code.

@tannerlinsley
Copy link
Collaborator

If you can, do this outside of the footer function for performance reasons. If you have a small dataset though, you could do it in the render function of the column footer:

Outside of column, more performant

const data = [...]

let ageSum = 0
for (let i = 0; i <= data.length; i++) {
  ageSum += data[i].age
}

const columns = [{
  header: 'Age',
  footer: 'Total: ' + ageSum
}]

Inside column, less performant

const data = [...]

const columns = [{
  header: 'Age',
  footer: () => {
    let ageSum = 0
    for (let i = 0; i <= data.length; i++) {
      ageSum += data[i].age
    }
    return 'Total: ' + ageSum
  }
}]

@vinodkhandelwal
Copy link
Author

vinodkhandelwal commented Feb 28, 2017

Thanks a lot for response. However, with this solution it is rendering value as 0. here is my code snippet.

var marketValSum = 0;
var cashSum = 0;

const columns = [
    { accessor: 'name', header: 'Name',width: 205 },
    { accessor: 'marketValue', header: 'Market Value', footer: 'Total: ' + marketValSum},
    { accessor: 'cash', header: 'Cash', footer: 'Total: ' + marketValSum}
 ];

const AccountsGrid = (props) => {

    const accountData = props.accounts;
   if(accountData.length >0) {
        for (let i = 0; i < accountData.length; i++) {
          marketValSum += accountData[i].marketValue;
          cashSum += accountData[i].cash;
        }
    }

    return (
        <ReactTable
            columns={columns}
            data={props.accounts}
            className='-striped -highlight'
            defaultPageSize={10}
            />
    );
};

@tannerlinsley
Copy link
Collaborator

Try this:

const AccountsGrid = (props) => {

    var marketValSum = 0;
    var cashSum = 0;
    
    const accountData = props.accounts;
    
    if(accountData.length >0) {
        for (let i = 0; i < accountData.length; i++) {
          marketValSum += accountData[i].marketValue;
          cashSum += accountData[i].cash;
        }
    }

    const columns = [
      { accessor: 'name', header: 'Name',width: 205 },
      { accessor: 'marketValue', header: 'Market Value', footer: 'Total: ' + marketValSum},
      { accessor: 'cash', header: 'Cash', footer: 'Total: ' + cashSum}
    ]

    return (
      <ReactTable
        columns={columns}
        data={props.accounts}
        className='-striped -highlight'
        defaultPageSize={10}
      />
    );
};

@vinodkhandelwal
Copy link
Author

It works. thanks a lot.

@zarela
Copy link

zarela commented Jan 19, 2018

You could also do this:

<span>{_.sum(_.map(data, d => d.total))}</span>

if your columns look like this:

  const columns = [
       {
         Header: 'Total',
         accessor: 'total',
         id: 'total',
         Cell: props => <span>{props.value}</span>,
         Footer: <span>{_.sum(_.map(data, d => d.total))}</span>
       }
     ]

@Mike-SP
Copy link

Mike-SP commented May 10, 2018

I've been able to make the code above work, however, if my table is filterable, when the table displays a set of filtered rows, the footer sums do not change to match the rows. How can I make it recalculate the sum of the filtered rows only?

@gary-menzel
Copy link
Contributor

@Mike-SP
Instead of doing your aggregation on your raw data you need to add a ref to ReactTable and then call getResolvedState() on the ref to get the sortedData (which is also the filtered data) and aggregate over that.

https://github.com/react-tools/react-table/wiki/FAQ#how-do-i-get-at-the-internal-data-so-i-can-do-things-like-exporting-to-a-file

@RokHoang
Copy link

@gary-menzel How to change the value of footers? I can get filtered data but don't know how to change the footer. Can you give me an example?

@phares
Copy link

phares commented Mar 12, 2019

Footer: {.sum(.map(data, d => d.total))}

Hi @zarela am getting an error '_' is not defined no-undef

@thomasserio
Copy link

@phares Make sure you are importing lodash to use _

@ofrades
Copy link

ofrades commented Feb 1, 2021

If the data in the table was editable would this work to update the sum value accordingly?

@Ribosom
Copy link

Ribosom commented Nov 23, 2021

For me the solution with getResolvedState didn't work to get it working with filters.

Howerver, I did find another solution. Here is my footer definition, for a the sum of a column with costs-data:

{
    Header: "Costs",
    accessor: "costs",
    Footer: info => _.sum(info.filteredRows.map(row => row.values.costs))
}

@n18l
Copy link

n18l commented Aug 26, 2022

For anyone who stumbles on this like I did, here's a current method that worked for me. It uses the native JavaScript Array.reduce instead of Lodash's sum method, but either would work.

{
  accessorKey: 'your_accessor_key',
  footer: ({ table }) => table.getFilteredRowModel().rows.reduce((total, row) => total + row.getValue('your_accessor_key'), 0),
}

Note that you may need to cast the return value of row.getValue() to a number to properly sum it.

@KevinVandy
Copy link
Member

For anyone who stumbles on this like I did, here's a current method that worked for me. It uses the native JavaScript Array.reduce instead of Lodash's sum method, but either would work.

{
  accessorKey: 'your_accessor_key',
  footer: ({ table }) => table.getFilteredRowModel().rows.reduce((total, row) => total + row.getValue('your_accessor_key'), 0),
}

Note that you may need to cast the return value of row.getValue() to a number to properly sum it.

This works, but also can lead to heavy calculations during renders. Consider doing calculations like this in a useMemo based on the data itself

@sandeepd4d
Copy link

For anyone who stumbles on this like I did, here's a current method that worked for me. It uses the native JavaScript Array.reduce instead of Lodash's sum method, but either would work.

{
  accessorKey: 'your_accessor_key',
  footer: ({ table }) => table.getFilteredRowModel().rows.reduce((total, row) => total + row.getValue('your_accessor_key'), 0),
}

Note that you may need to cast the return value of row.getValue() to a number to properly sum it.

I am getting the total of age in my scenario.
Total of age's column is working fine but when I update any age with negative value, I get the total wrong. like my total is 200 and I update age from 20 to -20 then it will reduce 40 from 200 instead of 20. Can anyone explain why?

@RaGreen
Copy link

RaGreen commented Jul 24, 2023

@sandeepd4d Difference between 20 and -40 is 40 :) It would be 20, if you change 20 to 0.

@NatalliaSh
Copy link

NatalliaSh commented Dec 13, 2023

Hello, could you please help with rendering footer.
I calculated the sum and difined it like in example, but it doesn't appear in table
here is column definition

data.columns.map((col) => ({
        accessorKey: col.id,
        cell: EditableCell,
        footer: ({table}: FooterProps) => {
          const sum = table
            .getFilteredRowModel()
            .rows.reduce((acc, row, index) => {
              if (index === 0) {
                return acc;
              }
              const value: number = parseInt(
                (row.getValue(col.id) as ValueType).value,
              );

              return isNaN(value) ? acc : acc + value;
            }, 0);

          return `${sum}`;
        },`
```
        
and I'm trying to render footer like:
`

`
```
<tfoot>
          {table.getFooterGroups().map((footerEl) => (
            <tr key={footerEl.id}>
              {footerEl.headers.map((columnEl) => (
                <th key={columnEl.id} colSpan={columnEl.colSpan}>
                  {flexRender(
                    columnEl.column.columnDef.footer,
                    columnEl.getContext(),
                  )}
                </th>
              ))}
            </tr>
          ))}
        </tfoot>
```

@9mm
Copy link

9mm commented Jan 19, 2024

how do we actually use

        aggregationFn: "sum",

There is no documentation or examples anywhere that I can find, and I see no intuitive way to use this

@9mm
Copy link

9mm commented Jan 19, 2024

<tfoot v-if="table.getFooterGroups().length">
  <tr v-for="footerGroup in table.getFooterGroups()" :key="footerGroup.id">
    <td v-for="cell in footerGroup.headers" :key="cell.id" :colspan="cell.colSpan" :class="['select-none', { 'footer-group': cell.column.columnDef.columns?.length }]">
      <flex-render :render="cell.column.columnDef.footer" :props="cell.getContext()" />
    </td>
  </tr>
</tfoot>

I tried cell.column.columnDef.aggregatedCell in my footer but it just returns an error

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests