1
votes

I have a page with a Material table. The table has a custom data source since pagination is server side. It also has a check box column. The rows in the table are expandable.

Problem: The expandable rows work fine until I go to some other page and reroute to the above page again. When I reroute back to the page many rows are in expanded state automatically.

I found one question with a similar issue : Similar problem However I don't have tabs so the solution mentioned can't be applied to my problem and fundamentally I am not sure why the solution works.

Code snippet which adds the expandable row to the table:

<ng-container matColumnDef="expandedDetail">
      <td mat-cell *matCellDef="let element" [attr.colspan]="displayedColumns.length">
        <div [@detailExpand]="element === expandedElement ? 'expanded' : 'collapsed'">
         <div>Expandable row details go here</div>
        </div>
      </td>
    </ng-container>

    <mat-header-row *matHeaderRowDef="displayedColumns; sticky:true"></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns"
      (click)="toggle(row); expandedElement = expandedElement == row ? null : row"
      [class.element-expanded-row]="expandedElement == element" class="clickable-row element-row">
    </mat-row>
    <mat-row *matRowDef="let row; columns: ['expandedDetail'];"
      [@detailExpand]="row === expandedElement ? 'expanded' : 'collapsed'">
    </mat-row>
  </mat-table>

In the TS file I have a variable which I reset to null on ngOnInit:

expandedElement: any;

Also, One more behavior that I observed when I come back to the page was that I have to click the row twice to close it which means the condition to collapse and open the row (element === expandedElement) is satisfied just that the row is visible when I come back to the page.

Does any one has any clue what may be the problem?

Edit :

The expandable table example on angular materials page doesn't have to use [@detailExpand] for the expand detail mat-row however I have to use otherwise I see a empty row in between 2 rows of data. Why so? Does it have to do anything with this problem?

 <mat-row *matRowDef="let row; columns: ['expandedDetail'];"
      [@detailExpand]="row === expandedElement ? 'expanded' : 'collapsed'">
    </mat-row>
2
have you tried setting expandedElement to undefined when the user gets routed to the page? - Stefan
I was already setting it to null. Just tried undefined. Doesn't fix the bug. - humbleCoder

2 Answers

0
votes

By default, the tab contents are eagerly loaded.
Eagerly loaded tabs will initalize the child components but not inject them into the DOM until the tab is activated.

If the tab contains several complex child components or the tab's contents rely on DOM calculations during initialization, it is advised to lazy load the tab's content.
(The expandable table is based on DOM calculations)

Tab contents can be lazy loaded by declaring the body in a ng-template with the matTabContent attribute.

Search for lazy loading in https://material.angular.io/components/tabs/overview


EDIT
I don't know what you are trying to do but the simple expandable table in angular is like this:

<table mat-table
       [dataSource]="dataSource" multiTemplateDataRows
       class="mat-elevation-z8">
  <ng-container matColumnDef="{{column}}" *ngFor="let column of columnsToDisplay">
    <th mat-header-cell *matHeaderCellDef> {{column}} </th>
    <td mat-cell *matCellDef="let element"> {{element[column]}} </td>
  </ng-container>

  <!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
  <ng-container matColumnDef="expandedDetail">
    <td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplay.length">
      <div class="example-element-detail"
           [@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
        <div class="example-element-description">
         here the data you want to display
        </div>
      </div>
    </td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="columnsToDisplay; sticky:'true'"></tr>
  <tr mat-row *matRowDef="let row; columns: columnsToDisplay;"
      class="example-element-row"
      [class.example-expanded-row]="expandedElement == element"
      (click)="toggle(row); expandedElement = expandedElement === row ? null : row">
  </tr>
  <tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
</table>
<mat-paginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons></mat-paginator>

DETAIL EXPAND

This is used for trigger the animation

@Component({
  selector: "table-expandable-rows-example",
  styleUrls: ["table-expandable-rows-example.css"],
  templateUrl: "table-expandable-rows-example.html",
  animations: [
    trigger("detailExpand", [
      state("collapsed", style({ height: "0px", minHeight: "0" })),
      state("expanded", style({ height: "*" })),
      transition(
        "expanded <=> collapsed",
        animate("225ms cubic-bezier(0.4, 0.0, 0.2, 1)")
      )
    ])
  ]
})
0
votes

This issue describes the same problem. Basically Sorting breaks animation. In my case as well if I turn off sorting the animation works fine.

Final solution : Use ngClass with CSS animations. Got the solution from the following answer : https://stackoverflow.com/a/65198370/1711670.