Components: Table with dynamic columns - footer / header does not update after context change

Created on 7 Sep 2018  路  9Comments  路  Source: angular/components

Bug, feature request, or proposal:

Bug

What is the expected behavior?

I define table using dynamic columns like below. In footer cell definition I am using some context object (from current component) and its values.

After context object is updated, table footer displays current data.

        <ng-container
            *ngFor="let month of months;"
            matColumnDef="p{{month}}"
        >
            <th mat-header-cell *matHeaderCellDef>
                {{month}}
            </th>
            <td
                mat-cell
                *matCellDef="let element"
            >
                        {{element.someValue}}
            </td>
            <td mat-footer-cell *matFooterCellDef>
                   {{someContextObject?.someValue}}
            </td>
        </ng-container>

What is the current behavior?

After updating context object, table footer does not show changes. It does not work even, if context variable is a simple string.

This works correctly, if table cell is not defined using *ngFor.

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Angular Material 6.4.7

Most helpful comment

Further to the issues noted by @literalpie above, I have more workarounds for those interested.

Having noted the 'changed' flags as part of removeHeaderRowDef() and removeFooterRowDef()
https://github.com/angular/material2/blob/21e646a3e7d99323e3f6d1e2961f416c8695bf48/src/cdk/table/table.ts#L555
https://github.com/angular/material2/blob/21e646a3e7d99323e3f6d1e2961f416c8695bf48/src/cdk/table/table.ts#L567

here are some change detection workarounds for header/footer rows:

  • header rows cannot be ngIfd --> use table.removeHeaderRowDef(null) to trigger an update to the header (or table.removeFooterRowDef(null))

See updated stackblitz - note that toggling booly refreshes table header and body rows correctly.

All 9 comments

Update - I have been able to make a work around for this using separate ng-template (outside of ng-container), like below. But this is absurd, especially for footer cells, which often show aggregate values (totals) from outside of table data source.

<ng-container
            *ngFor="let month of months;"
            matColumnDef="p{{month}}"
        >
            <th mat-header-cell *matHeaderCellDef>
                {{month}}
            </th>
            <td
                mat-cell
                *matCellDef="let element"
            >
                        {{element.someValue}}
            </td>
            <td mat-footer-cell *matFooterCellDef>
                   <ng-container *ngTemplateOutlet="monthFooter;context: {month: month}"></ng-container>
            </td>
</ng-container>

 <ng-template #monthFooter let-month="month">
                {{someContextObject?.someValue}}
 </ng-template>

Can you provide a reproduction in StackBlitz. This will help us to investigate the issue you are seeing.

It's interesting - I cannot reproduce it on StackBlitz right now using simple table implementation. I am seeing this in my code, though. I will have to extend StackBlitz example to reproduce the exact conditions I have.

@josephperrott Hi! I'm having what I think may be a similar issue. I was able to reproduce it on stackblitz.

The stackblitz actually includes a few change detection issues.

  • If you toggle something first, and then toggle booly, the first column doesn't update to represent the change in boolys value. I think this has to do with the ngIf
  • header rows cannot be ngIfd
  • ngIfd mat-rows are not updated unless a sort button is pressed (although, this can be worked-around by calling table.renderRows() - Maybe this is expected?)

edit: one more:

  • the booly value in the name header does not update until you hover over a sortable column header (No.)

Can confirm this is an issue as well. Using @TiS solution with ng-template as a workaround. Issue happens when dataSource is given a whole new data array in ngOnChanges.

  ngOnChanges(changes: { [propKey: string]: SimpleChange }) {
    if ('data' in changes && !changes['data'].isFirstChange() && this.data) {
      this.dataSource.data = [...this.data.report.data];

Further to the issues noted by @literalpie above, I have more workarounds for those interested.

Having noted the 'changed' flags as part of removeHeaderRowDef() and removeFooterRowDef()
https://github.com/angular/material2/blob/21e646a3e7d99323e3f6d1e2961f416c8695bf48/src/cdk/table/table.ts#L555
https://github.com/angular/material2/blob/21e646a3e7d99323e3f6d1e2961f416c8695bf48/src/cdk/table/table.ts#L567

here are some change detection workarounds for header/footer rows:

  • header rows cannot be ngIfd --> use table.removeHeaderRowDef(null) to trigger an update to the header (or table.removeFooterRowDef(null))

See updated stackblitz - note that toggling booly refreshes table header and body rows correctly.

Not sure if it is the same root-cause, but I encountered the following problem:

Context:
I have a footer with input fields to add new lines to the table, but only if it is allowed to edit the table values:

<ng-container *ngIf="editable">
    <mat-footer-row...>
    </mat-footer-row>
</ng-container>

works perfect when I statically set
[editable]="true" or ="false"

but not when I use an @Input() Setter and have a dynamic value like
[editable]="valueReceivedAsyncFromServer"

Workaround:
I'm always rendering the footer but hiding it with css (using ng flexlayout in my case):

    <mat-footer-row [fxHide]="!editable" ...>
    </mat-footer-row>

not ideal

This issue has grown to include several different issues. It would help us a lot if each issue is opened independently so that we can track them, especially with provided stackblitz reproductions.

Please note that using ng-container around the rows is not our recommended approach to rendering different rows, instead please use the when predicate.

With regards to the first issue, it sounds like it could not be reproduced in stackblitz for us to investigate. If it can, please re-open an issue with a link. Thanks!

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._

Was this page helpful?
0 / 5 - 0 ratings

Related issues

crutchcorn picture crutchcorn  路  3Comments

theunreal picture theunreal  路  3Comments

LoganDupont picture LoganDupont  路  3Comments

julianobrasil picture julianobrasil  路  3Comments

constantinlucian picture constantinlucian  路  3Comments