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

[Table] Add a footer row (e.g. totals) #7548

Closed
Knoxvillekm opened this issue Oct 5, 2017 · 27 comments · Fixed by #10330
Closed

[Table] Add a footer row (e.g. totals) #7548

Knoxvillekm opened this issue Oct 5, 2017 · 27 comments · Fixed by #10330
Assignees
Labels
feature This issue represents a new feature or feature request rather than a bug or bug fix needs: discussion Further discussion with the team is needed before proceeding P4 A relatively minor issue that is not relevant to core functions
Projects

Comments

@Knoxvillekm
Copy link

Bug, feature request, or proposal:

feature reques

What is the expected behavior?

Add total row:

  <md-table [dataSource]="dataSource">

    <!-- Name Column -->
    <ng-container mdColumnDef="name">
      <md-header-cell *mdHeaderCellDef> Name </md-header-cell>
      <md-cell *mdCellDef="let row"> {{row.name}} </md-cell>
      <md-total-cell *mdTotalCellDef> Total </md-total-cell>
    </ng-container>

    <!-- Count Column -->
    <ng-container mdColumnDef="count">
      <md-header-cell *mdHeaderCellDef> Count </md-header-cell>
      <md-cell *mdCellDef="let row"> {{row.count}} </md-cell>
      <md-total-cell *mdTotalCellDef> {{dataSource.sumBy('count')}} </md-total-cell>
    </ng-container>

    <md-header-row *mdHeaderRowDef="displayedColumns"></md-header-row>
    <md-row *mdRowDef="let row; columns: displayedColumns;"></md-row>
    <md-total-row *mdTotalRowDef="displayedColumns"></md-total-row>
  </md-table>

Result:

Name       Count 
row 1       1        
row 2       2
Total       3

Or something like md-pagination.

  <md-table [dataSource]="dataSource">

    <!-- Name Column -->
    <ng-container mdColumnDef="name">
      <md-header-cell *mdHeaderCellDef> Name </md-header-cell>
      <md-cell *mdCellDef="let row"> {{row.name}} </md-cell>
    </ng-container>

    <!-- Count Column -->
    <ng-container mdColumnDef="count">
      <md-header-cell *mdHeaderCellDef> Count </md-header-cell>
      <md-cell *mdCellDef="let row"> {{row.count}} </md-cell>
    </ng-container>

    <md-header-row *mdHeaderRowDef="displayedColumns"></md-header-row>
    <md-row *mdRowDef="let row; columns: displayedColumns;"></md-row>
  </md-table>

  <md-table-total [dataSource]="dataSource">

    <!-- Name Column -->
    <ng-container mdColumnDef="name">
      <md-total-cell *mdTotalCellDef> Total </md-total-cell>
    </ng-container>

    <!-- Count Column -->
    <ng-container mdColumnDef="count">
      <md-total-cell *mdTotalCellDef> {{dataSource.sumBy('count')}} </md-total-cell>
    </ng-container>
  </md-table-total>
@willshowell
Copy link
Contributor

See #6570

@jelbourn jelbourn added discussion feature This issue represents a new feature or feature request rather than a bug or bug fix labels Oct 5, 2017
@jelbourn
Copy link
Member

jelbourn commented Oct 5, 2017

@andrewseguin it's probably worth talking about a more convenient shortcut for adding a summary row at some point

@andrewseguin andrewseguin self-assigned this Oct 6, 2017
@andrewseguin
Copy link
Contributor

To be clear - this is meant to be a sticky footer at the bottom rather than a "last row"?

@jelbourn
Copy link
Member

jelbourn commented Oct 6, 2017

I think so, but we should collect a few use-cases before committing to anything.

@andrewseguin
Copy link
Contributor

andrewseguin commented Oct 6, 2017

Since the table itself doesn't have knowledge of its scrollable container (its just a repeat of rows), I wonder if this would be out of scope. We should definitely chat more about this (and the sections feature seems similar actually).

In the meantime, a solution to this would be to create a new table and append it right after the initial table. Hide the header row and keep the column IDs similar (to re-use any column-specific class styles you might have).

This way, the table can be its own scrollable and the footer could just append right after the scrolling container.

A separate data source should be provided since the data is unique.

Here's a proof of concept
https://plnkr.co/edit/vZz0ZuMII8Pudd0zMewC?p=preview

Unfortunately most browsers push content left when a scrollbar appears, so it's likely that the columns will be misaligned for most users :(

Edit: Reminds me of a simple solution for sticky headers as well =P

@willshowell
Copy link
Contributor

I was making this to supplement #6570 (comment), but figure I'll add it here as an alternative solution in the mean-time,

https://stackblitz.com/edit/material2-beta12-fkcu2t

cc @Tempus35

@timwright35
Copy link

@willshowell Thanks!

@pantonis
Copy link

This is a very important feature for a datatable. Since datatables are used mostly for showing numeric tabular data, totals is a must feature.

@andrewseguin andrewseguin added this to Features in Table Oct 19, 2017
@andrewseguin andrewseguin moved this from Features to Discussion in Table Oct 19, 2017
@andrewseguin andrewseguin added the P4 A relatively minor issue that is not relevant to core functions label Oct 19, 2017
@andrewseguin andrewseguin changed the title feature request(table): Add total row [Table] Add a footer row (e.g. totals) Oct 19, 2017
@pantonis
Copy link

pantonis commented Nov 5, 2017

@andrewseguin Why is this minor? Is there any workaround that works without any issues? From what you said your workaround above does not work well. :)

@timwright35
Copy link

I was just wondering if the discussion was still happening on this or if this is dead in the water. Could really use this in my current project.

@pantonis
Copy link

pantonis commented Jan 18, 2018

Such a nice table with lot of features but one of the most critical features of tabular data is missing. This missing feature prevents me from using material datatable.

@padilla-jm
Copy link

I agree, this is something that is used all the time with tables.

@andrewseguin
Copy link
Contributor

Definitely still on our radar. Will likely call this something like mat-footer-row and implement it similarly to the header and data rows.

Unfortunately its minor compared to other features. Just gotta find some priority with respect to all the features we want on the table. Right now my biggest priority is reducing the pain in setting up the table (e.g. easier to make data sources, allow data arrays for simplicity, make it easier to define columns)

@pantonis
Copy link

I think it already became quite simple to setup the table compared to previous versions. Never mind though didnt have morentime to wait switched to another table already. Keep up the good work

@GoLucas
Copy link

GoLucas commented Feb 12, 2018

@willshowell how can i use your solution on my async datasource ?

  onChange(event) {
    this.dataSource = new ReservationDataSource(this.paymentsData, event.value);
}
export class ReservationDataSource extends DataSource<any> {
  reservation_id: any;
  constructor(private paymentsData: UserPaymentsService, reservation_id: any) {
    super();
    this.reservation_id = reservation_id;
  }
  connect(): Observable<Payment[]> {
    return this.paymentsData.httpGetPayments(this.reservation_id); 
  }
}

@willshowell
Copy link
Contributor

@GoLucas you could try something like this:

interface Payment {
  date: Date;
  cost: number;
}

interface PaymentTotal {
  total: number;
}

// ...

connect(): Observable<(Payment | PaymentTotal }[]> {
  return this.paymentsData.httpGetPayments(this.reservation_id)
    // Append a 'total' row at the end
    .map(payments => {
      const paymentsSum = payments.reduce((accum, curr) => accum + curr.cost), 0);
      return [...payments, { total: paymentsSum }];
    });
}

@GoLucas
Copy link

GoLucas commented Feb 12, 2018

@willshowell i have one more question how can i get isLastRow like in example below https://stackblitz.com/edit/material2-beta12-fkcu2t?file=app%2Fapp.component.ts

@willshowell
Copy link
Contributor

@GoLucas a simple way would be to save it in the datasource:

// In your datasource
public totalRowIndex;

connect(): Observable<(Payment | PaymentTotal }[]> {
  return this.paymentsData.httpGetPayments(this.reservation_id)
    // Append a 'total' row at the end
    .map(payments => {
      const paymentsSum = payments.reduce((accum, curr) => accum + curr.cost), 0);
      return [...payments, { total: paymentsSum }];
    })
    .do(payments => this.totalRowIndex = payments.length - 1);
}
// In your component class
isLastRow = (data, index) => index === this.dataSource.totalRowIndex;

@GoLucas
Copy link

GoLucas commented Feb 13, 2018

in my case still dont work
image

i im initialize datasource on change event in select

  onChange(event) {
    const isLastRow = (data, index) => index === this.dataSource.totalRowIndex;
    this.dataSource = new ReservationDataSource(this.paymentsData, event.value);
}

when i move isLastRow on the top under Class i have one additional empty row.
and this is my html:

image

@dushkostanoeski
Copy link

Is there any progress on this matter, or some ETA?

@andrewseguin
Copy link
Contributor

@GoLucas

Your component should have this as a property:
isLastRow = (data, index) => index === this.dataSource.totalRowIndex;

E.g.

export class MyComponent {
  ...
  isLastRow = (data, index) => index === this.dataSource.totalRowIndex;
  ...
}

@rain01
Copy link

rain01 commented Mar 15, 2018

This works for me for detecting the last row...

<mat-row *matRowDef="let row; columns: displayedColumns; let last = last;" [ngClass]="{'last-table-row': last}"></mat-row>

Except it's still useless with sorting.
Really could use footer right about now.

@andrewseguin
Copy link
Contributor

@rain01 Nearly there, got a PR open that will add a footer row #10330

@rain01
Copy link

rain01 commented Mar 27, 2018

Thanks, yup. I saw there's The Travis CI build failed. Right now I'm using a workaround which works great for simpler things with sorting. Haven't tested it with pagination yet though.

Just put this below mat-table.

<div class="mat-table" role="grid">
    <div class="mat-header-row" role="row">
        <div class="mat-header-cell" role="columnheader">{{ row.name }}</div>
        <div class="mat-header-cell" role="columnheader">{{ row.age }}</div>
        <div class="mat-header-cell" role="columnheader">{{ row.count }}</div>
    </div>
</div>

@sivahanuman
Copy link

Hi any working total footer column on https://stackblitz.com example with paging and sorting

@sivahanuman
Copy link

Hi Mr.rain,
Can you post the working solution on stackblitz.

Table automation moved this from Discussion to Closed Apr 23, 2018
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 8, 2019
@mmalerba mmalerba added the needs: discussion Further discussion with the team is needed before proceeding label Mar 3, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feature This issue represents a new feature or feature request rather than a bug or bug fix needs: discussion Further discussion with the team is needed before proceeding P4 A relatively minor issue that is not relevant to core functions
Projects
No open projects
Table
  
Closed