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

CDK table inappropriately rerenders table header cells when there are multiple headers #29922

Closed
anthonyrgreen opened this issue Oct 24, 2024 · 1 comment · Fixed by #30012
Closed

Comments

@anthonyrgreen
Copy link

anthonyrgreen commented Oct 24, 2024

Which @angular/* package(s) are the source of the bug?

Don't known / other

Is this a regression?

No

Description

Tl;dr: See a minimal repro with root-cause, explanation, and potential fix here: https://stackblitz.com/edit/angular-material-table-multiple-header-rows-nj2ljf?file=app%2Ftable-basic-example.html

If I create a mat-table, and give it multiple header rows like so:

    <tr mat-header-row *matHeaderRowDef="displayedHeaderColumns"></tr>
    <tr mat-header-row *matHeaderRowDef="displayedSubheaderColumns"></tr>

Then, when I append a column to the inner values of both displayedHeaderColumns and displayedHeaderColumns, the cdk-table change-detection code renders the table into a 'dirty' state. The result of this is that, on the first dirty-check of the table, the table headers rerender, destroying and recreating all the <th mat-header-cell> elements and preempting any interaction handlers in progress. This prevents e.g. button clicks from being registered, and, in my app, stops a menu from opening from the table header.

This phenomenon only occurs on the FIRST click post-column-add, and only if you include the 2nd (sub)header in your table definition, i.e. commenting out <tr mat-header-row *matHeaderRowDef="displayedSubheaderColumns"></tr> mitigates the bug.

Possible root cause of the bug

I think this is happening because Angular somehow rerenders the subheader as a result of dirty-checking the header, but does not update its internal records of the subheader's state in the process. Clicking the button causes the table to re-check its subheader's columns, at which point its differ discovers it hasn't officially added the newest column to the list (although it is already visually displaying the newest column).

This bug disappears if I modify CdkTable._renderUpdatedColumns in the following manner at angular/components/src/cdk/table/table.ts:1087:

Original code:

  const columnsDiffReducer = (acc: boolean, def: BaseRowDef) => 
    acc || !!def.getColumnsDiff();

Fixed code:

  const columnsDiffReducer = (acc: boolean, def: BaseRowDef) => {
    const diff = def.getColumnsDiff();
    return acc || !!diff;
  };

I think that the lazy computation of def.getColumnsDiff() is causing the subheader state not to get updated.

Please provide a link to a minimal reproduction of the bug

https://stackblitz.com/edit/angular-material-table-multiple-header-rows-nj2ljf?file=app%2Ftable-basic-example.html

Please provide the exception or error you saw

There is no exception. The error is that, when the user clicks their first button on a table header, all the table headers rerender, destroying and recreating each <th mat-header-cell> element and preempting any interaction handlers in progress. This prevents e.g. button clicks from being registered, and, in my app, stops a menu from opening from the table header.

Please provide the environment you discovered this bug in (run ng version)

{
"name": "xokrrnnaegq.angular",
"version": "0.0.0",
"private": true,
"dependencies": {
"rxjs": "6.4.0",
"moment": "2.24.0",
"core-js": "2.6.4",
"zone.js": "0.8.29",
"hammerjs": "2.0.8",
"@angular/cdk": "7.3.1",
"@angular/core": "7.2.4",
"@angular/http": "7.2.4",
"@angular/forms": "7.2.4",
"@angular/common": "7.2.4",
"@angular/router": "7.2.4",
"@angular/compiler": "7.2.4",
"@angular/material": "7.3.1",
"web-animations-js": "2.3.1",
"@angular/animations": "7.2.4",
"@angular/platform-browser": "7.2.4",
"angular-in-memory-web-api": "0.5.4",
"@angular/material-moment-adapter": "7.3.1",
"@angular/platform-browser-dynamic": "7.2.4",
"@ngrx/store": "^18.1.0"
},
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.10.0",
"@angular/cli": "~7.0.2",
"@angular/compiler-cli": "~7.0.0",
"@angular/language-service": "~7.0.0",
"@types/node": "~8.9.4",
"@types/jasmine": "~2.8.8",
"@types/jasminewd2": "~2.0.3",
"codelyzer": "~4.5.0",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~3.0.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~1.1.2",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.11.0",
"typescript": "~3.1.1"
}
}

Anything else?

No response

@anthonyrgreen anthonyrgreen changed the title Mat table inappropriately rerenders table header cells when there are multiple headers CDK table inappropriately rerenders table header cells when there are multiple headers Oct 24, 2024
anthonyrgreen referenced this issue in anthonyrgreen/components Oct 24, 2024
@JeanMeche JeanMeche transferred this issue from angular/angular Oct 25, 2024
@andrewseguin andrewseguin reopened this Nov 13, 2024
@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 Dec 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants