Ngx-datatable: Automatic summary row basing on given function

Created on 30 Dec 2017  路  21Comments  路  Source: swimlane/ngx-datatable








I'm submitting a ... (check one with "x")

[ ] bug report => search github for a similar issue or PR before submitting
[x] feature request
[ ] support request => Please do not submit support request here, post on Stackoverflow or Gitter

Current behavior
Currently, the only way to make some kind of summary is to add some manually calculated metrics to a footer of a table.

Expected behavior
I want to have a separate row for a summary like here: https://imgur.com/a/2VziI. A width of each cell should be the same as rest of table. In addition, it should act as a regular row and as a user, I want to define a function which will compute a value for each cell in such row. That will be nice if I will be able to set a position of summary row: either top or bottom of a page.

Reproduction of the problem

What is the motivation / use case for changing the behavior?
The current solution is unreadable in case of a table with many columns.

Please tell us about your environment:
Arch Linux, Node 9.3.0, Angular 5

  • Table version: 11.1.7

  • Angular version: 5.0.3

  • Browser: [all]

  • Language: [all]

Most helpful comment

Hello again, I think I figure out how to implement that feature and I want to share some kind of the feature specification.

Introduction

The main purpose of the summary row is to improve readability of the aggregated data. Each column can have its own cell which shows generally defined "summary" - it can be just a sum of all cells in the column, a user-defined text or even a custom template.

Position

According to many popular websites, the position of the row can be changed and could be:

  • on top, right below the headers row,
  • on bottom, right above footer

Interface

There are many aspects of the row which can be configured. Basically, you can enable the summary using a new ngx-datatable HTML attribute:

<ngx-datatable [summaryRow]="true"></ngx-datatable>

That line will enable the summary row with the basic configuration:

  • standard HTML template
  • summary at the bottom of the table
  • + operator as the summary function

The position of the summary row can be modified via summaryPosition input:

<ngx-datatable [summaryRow]="true" [summaryPosition]="'top'"></ngx-datatable>

Correct values are top and bottom (the default value).

The standard behaviour can be overridden by column definition which will be extended by new field summaryFunc:

HTML

<ngx-datatable [summaryRow]="true" [columns]="columns"></ngx-datatable>

TS

columns = [
  # basic sum function
  { name: 'Column1', summaryFunc: (cells) => cells.reduce((sum, cell) => sum += cell) },
  # more sophisticated example
  { name: 'Column2', summaryFunc: (cells) => 'First row have value ' + cells[0] },
];

The users which want to take a full control of rendered content can use field summaryTemplate which will take ElementRef as a value:

HTML

<ngx-datatable [summaryRow]="true" [columns]="columns"></ngx-datatable>
<ng-template #customSummaryCell let-cells="cells">
  <div class="super-custom-style">{{ customFunc(cells) }}</div>
</ng-template>

TS

@ViewChild('customSummaryCell')
customSummaryCell: TemplateRef<any>;
columns = [];

ngOnInit() {
  columns = [
    { name: 'With custom template', summaryTemplate: customSummaryCell }
  ];
}

customFunc(cells: any[]) {
  return 'Some kind of magic ' + Math.random() + cells[0];
}

Thanks to @farhanmughal222 summary row works also with inline HTML syntax:

HTML

<ngx-datatable [summaryRow]="true" [rows]="rows">
  <ngx-datatable-column prop="prop1" [summaryFunc]="summaryForProp1"></ngx-datatable-column>
  <ngx-datatable-column name="Prop2" [summaryTemplate]="templateForProp2"></ngx-datatable-column>
</ngx-datatable>
<ng-template #templateForProp2>
  <div class="custom-template-body">
    {{ summaryForProp2() }}
  </div>
</ng-template>

TS

rows = [ // data ];
// no columns definition!

summaryForProp1(cells: any[]) {
  return 'Inline summary: ' + cells[0];
}

summaryForProp2() {
  return this.rows.map(row => row['Prop2'])
    .reduce((res, cell) => res += cell, 0);
}

In case of some basic styling, you can hook to standard summary row classes which will be:

  • .datatable-summary-row .datatable-body-row - for whole row
  • datatable-summary-row .datatable-body-cell - for single summary cell

Summary row a pagination

In the case of client site sorting, summaryFunc will receive values from all pages which are different from server-side sorting: in that case, you will receive only data from the current page. The solution is to plug your own fetch login to summaryFunc.

I'll start implementation in the next week. I'd like to hear your thoughts about this piece of specification guys.

All 21 comments

I want to offer help with writing that feature if you like to have it.

I was going to request this feature last week so please consider implementing this! I would like for the summary to sit above the pagination and stick, to allow the content to be scrolled normally. (eg. each column should have a 'totals' column that sits above the pagination bar as per the image: here) I would be willing to help where I can as well :)

@Corona17 so basically you want to exclude summary row from vertical scrolling area? Sounds like a good plan.
Let's not restrict the position of the summary to bottom (above footer/pagination) because many of professional looking pages have the summary at the top of a table (just below the header), for example, Google Analytics.
I'll take a deeper look into specification in the weekend.

@SirWojtek Yeah I think the summary row should be static and apart of the header or footer. I see the summary row as more for a 'totals' row, which is usually above the footer but having the option for top or bottom positioning should be good :)

Hello again, I think I figure out how to implement that feature and I want to share some kind of the feature specification.

Introduction

The main purpose of the summary row is to improve readability of the aggregated data. Each column can have its own cell which shows generally defined "summary" - it can be just a sum of all cells in the column, a user-defined text or even a custom template.

Position

According to many popular websites, the position of the row can be changed and could be:

  • on top, right below the headers row,
  • on bottom, right above footer

Interface

There are many aspects of the row which can be configured. Basically, you can enable the summary using a new ngx-datatable HTML attribute:

<ngx-datatable [summaryRow]="true"></ngx-datatable>

That line will enable the summary row with the basic configuration:

  • standard HTML template
  • summary at the bottom of the table
  • + operator as the summary function

The position of the summary row can be modified via summaryPosition input:

<ngx-datatable [summaryRow]="true" [summaryPosition]="'top'"></ngx-datatable>

Correct values are top and bottom (the default value).

The standard behaviour can be overridden by column definition which will be extended by new field summaryFunc:

HTML

<ngx-datatable [summaryRow]="true" [columns]="columns"></ngx-datatable>

TS

columns = [
  # basic sum function
  { name: 'Column1', summaryFunc: (cells) => cells.reduce((sum, cell) => sum += cell) },
  # more sophisticated example
  { name: 'Column2', summaryFunc: (cells) => 'First row have value ' + cells[0] },
];

The users which want to take a full control of rendered content can use field summaryTemplate which will take ElementRef as a value:

HTML

<ngx-datatable [summaryRow]="true" [columns]="columns"></ngx-datatable>
<ng-template #customSummaryCell let-cells="cells">
  <div class="super-custom-style">{{ customFunc(cells) }}</div>
</ng-template>

TS

@ViewChild('customSummaryCell')
customSummaryCell: TemplateRef<any>;
columns = [];

ngOnInit() {
  columns = [
    { name: 'With custom template', summaryTemplate: customSummaryCell }
  ];
}

customFunc(cells: any[]) {
  return 'Some kind of magic ' + Math.random() + cells[0];
}

Thanks to @farhanmughal222 summary row works also with inline HTML syntax:

HTML

<ngx-datatable [summaryRow]="true" [rows]="rows">
  <ngx-datatable-column prop="prop1" [summaryFunc]="summaryForProp1"></ngx-datatable-column>
  <ngx-datatable-column name="Prop2" [summaryTemplate]="templateForProp2"></ngx-datatable-column>
</ngx-datatable>
<ng-template #templateForProp2>
  <div class="custom-template-body">
    {{ summaryForProp2() }}
  </div>
</ng-template>

TS

rows = [ // data ];
// no columns definition!

summaryForProp1(cells: any[]) {
  return 'Inline summary: ' + cells[0];
}

summaryForProp2() {
  return this.rows.map(row => row['Prop2'])
    .reduce((res, cell) => res += cell, 0);
}

In case of some basic styling, you can hook to standard summary row classes which will be:

  • .datatable-summary-row .datatable-body-row - for whole row
  • datatable-summary-row .datatable-body-cell - for single summary cell

Summary row a pagination

In the case of client site sorting, summaryFunc will receive values from all pages which are different from server-side sorting: in that case, you will receive only data from the current page. The solution is to plug your own fetch login to summaryFunc.

I'll start implementation in the next week. I'd like to hear your thoughts about this piece of specification guys.

what if i don't want columns to be defined in ts like this and instead i need them inline html.
columns = [ { name: 'Description', prop: 'Item', flexGrow: 3, summaryFunc: () => null }, { name: 'Expenditures', prop: 'Expenses', flexGrow: 1, summaryFunc: (cells) => this.avgAge(cells) }, { name: 'Receipts' , prop: 'Reciepts', flexGrow: 1, summaryFunc: (cells) => this.avgAge(cells) }, { name: 'Accounting' , prop: 'Accounting', flexGrow: 2, summaryFunc: () => null }, ];

how can i apply inline summaryFunc in below columns:
<ngx-datatable-column name="Description" prop="Item" [flexGrow]="3" [resizeable]="false"></ngx-datatable-column> <ngx-datatable-column name="Expenditures" prop="Expenses" [flexGrow]="1" [resizeable]="false"></ngx-datatable-column> <ngx-datatable-column name="Receipts" prop="Reciepts" [flexGrow]="1" [resizeable]="false"></ngx-datatable-column> <ngx-datatable-column name="Accounting" prop="Accounting" [flexGrow]="2" [resizeable]="false"></ngx-datatable-column>

So you want to have a table with a structure defined only in HTML like that:

<ngx-datatable>
  <ngx-datatable-column></ngx-datatable-column>
  <ngx-datatable-column></ngx-datatable-column>
</ngx-datatable>

Current implementation didn't cover such case but it definetaly should.
I'll try to add support for that syntax to the PR connected to this issue. Thank you for your feedback, I really appreciate it!

@farhanmughal222 Good news! Now a summary row works with inline HTML syntax:

<ngx-datatable [summaryRow]="true" [rows]="rows">
  <ngx-datatable-column prop="prop1" [summaryFunc]="summaryForProp1"></ngx-datatable-column>
  <ngx-datatable-column name="Prop2" [summaryFunc]="summaryForProp2"></ngx-datatable-column>
</ngx-datatable>

Link to commit: https://github.com/swimlane/ngx-datatable/pull/1233/commits/ec98687d9f56b8097c08d4325275903b4e65ed81

@SirWojtek Thank you so much bro, you are life saver. 馃憤

@SirWojtek When this code will be pushed to the master of swimlane/ngx-datatable?

Haha, you're welcome :smiley: According to https://github.com/swimlane/ngx-datatable/pull/1233#issuecomment-364030162 we are waiting for the final approval from @amcdnl.

@SirWojtek [summaryTemplate]="nameSummaryCell" not working yet?

No, need more time to finish that. Should be available until end of this week.

@farhanmughal222 I've just finished summaryTemplate for inline HTML table. I hope you'll enjoy it and sorry for the delay!

@SirWojtek Greate job! I can't wait for your PR to be merged. Any hope to see it on master this week, maybe next week?

Can't wait to see this in master! My team has been eagerly awaiting this!

Hey @SirWojtek,
thank you for your work, it's nice and useful feature. But it seems that summaryRow with summaryPosition=bottom doesn't work when scrollbarV is turned on.
There is an example:
https://stackblitz.com/edit/angular-ngx-datatable-summary

Hello @ESadouski, thank you for your help. I've created a separate issue to keep track on this problem: https://github.com/swimlane/ngx-datatable/issues/1417. Could you check if I wrote down all information correctly?

Thank you. Everything is correct, except Table and Angular versions. I've reproduced it with ngx-datatable v12.0.0 and Angular 5.0.0

Hi @SirWojtek

Is the functionality to exclude the summary row from the vertical scrolling area available or still planned to be a feature?

Thanks!

Hey @JohnathanCena, right now I'm going to create a documentation explaining how to use a summary row but if you need that feature feel free to create a separate issue and mention me there. Cheers!

Was this page helpful?
0 / 5 - 0 ratings