5

I've a angular material table which uses detailRow directive to insert a detail/sibling adjacent row to a table row.

StackBlitz

I wanted to give it an appearance of as if the row is being expanded or collapsed, so I added couple of icons to it which are toggled on the click of cell containing them.

<mat-header-cell *matHeaderCellDef> Action </mat-header-cell>
      <mat-cell *matCellDef="let element"> 
         <button mat-icon-button color="primary"  (click)="element[i] = !element[i]">
            <mat-icon id="expand_more"  #expand_more *ngIf="!element[i] "  >expand_more</mat-icon>
            <mat-icon id="expand_less"  #expand_less *ngIf="element[i] ">expand_less</mat-icon>
          </button> 
      </mat-cell>

However if the I leave the row expanded and paginate or do a sort the icons do not toggle because there's no way for them to be toggled.

I've tried hooking into the page event or the sortChange event but came up empty.

I'm aware that there's new way to do expand/collapse in angular material v7 which probably works well with pagination and sort but its gonna be a while before I upgrade, in the mean time does anyone have any ideas on how to solve this.

kal93
  • 392
  • 1
  • 5
  • 20
  • The stackblitz example totally worked for me. I can expand and collapse the row after sorting and pagination – Ho Wei Lip Dec 14 '18 at 10:25
  • Are your icons still aligned when you paginate while leaving a row expanded? – kal93 Dec 14 '18 at 13:09
  • After sorting all the expanded rows become closed. But I am still able to interact with them after sorting or pagination. I am using linux and chrome. – Ho Wei Lip Dec 17 '18 at 02:38
  • can you click on the down arrow icon, and go to next page and then come back to first page and then take a look at the icon you clicked. Is the problem not clear in the question above? – kal93 Dec 17 '18 at 02:40
  • Okay I get the problem now. The problem only exist if you click away from the icon (Eg any where else on the row) – Ho Wei Lip Dec 17 '18 at 02:57
  • Can you please re-read the question particularly the lines below code snippet. Focus on icon. – kal93 Dec 17 '18 at 03:00
  • Do you need anymore clarification on the answer? – Ho Wei Lip Dec 19 '18 at 01:46
  • Sorry.Got pulled into another issue. I'll come back to this as soon as possible. Thank you very much for the detailed answer. – kal93 Dec 20 '18 at 08:24

1 Answers1

3

Short Answer

In cdk-detail-row.directive.ts add this

  ngOnDestroy(): void {
    this.row[undefined] = false;
  }

Long Answer

Firstly, You are capturing click in 2 places once in mat-row and the other in mat-cell(Clicking on the icon triggers both events. Clicking anywhere else on the row only triggers onToggleChange). And also this element[i] = !element[i] is a hack - (variable i is undefined). So if you click anywhere else in the row the expand icon does not change this is why I got confused as I thought it is not suppose to change. The example will just take out the click on mat-cell to make it simple.

In table-basic-example.html you should remove the (click) output from it and add the row argument to the method onToggleChange($event, row). And change the *ng-if to listen to element.close instead

<ng-container matColumnDef="expandCollapse">
  <mat-header-cell *matHeaderCellDef> Action </mat-header-cell>
  <mat-cell *matCellDef="let element"> 
     <button mat-icon-button color="primary">
        <mat-icon id="expand_more"  #expand_more *ngIf="!element.close"  >expand_more</mat-icon>
        <mat-icon id="expand_less"  #expand_less *ngIf="element.close">expand_less</mat-icon>
      </button> 
  </mat-cell>
</ng-container>

<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"
        class="element-row"
        [cdkDetailRow]="row" [cdkDetailRowTpl]="tpl"
        (toggleChange)="onToggleChange($event, row)">
</mat-row>

table-basic-example.ts

Add the close property to interface element

export interface Element {
    name: string;
    position: number;
    weight: number;
    symbol: string;
    close?: boolean;
}

Now we will handle the close and open of the row in the method onToggleChange.

onToggleChange(cdkDetailRow: CdkDetailRowDirective, row: Element): void {
    if (this.singleChildRowDetail && this.openedRow && this.openedRow.expended) {
        this.openedRow.toggle();
    }
    if (!row.close) {
        row.close = true;
    } else {
        row.close = false;
    }
    this.openedRow = cdkDetailRow.expended ? cdkDetailRow : undefined;
}

Lastly, In cdk-detail-row.directive.ts we will want to close the row once the directive is destroyed by pagination or toggling away. So we will implement the onDestroy method

export class CdkDetailRowDirective implements OnDestroy{
     ...Details of implementation.....
}

The new ngOnDestroy method should look like this

ngOnDestroy(): void {
  this.row.close = false;
}
Ho Wei Lip
  • 424
  • 3
  • 11
  • 1
    @WeiKipThank you very much.This works fine.I do have a another query regarding this which I will try to solve if I'm unable to do it then I will came back here and bother you again :). – kal93 Jan 05 '19 at 05:09
  • Yea sure no problem. Glad that I could help ^^. – Ho Wei Lip Jan 05 '19 at 07:16
  • How can I isolate click to only mat-icon but not on whole row? – Bozhinovski Aug 27 '19 at 13:33
  • Capture the click on the button instead and do the same thing as what happen when click is captured on cdkdetailed row. Remove the click host listen in the cdkdetail row. – Ho Wei Lip Aug 28 '19 at 07:06