Home > Back-end >  Expand/Collapse table rows - Angular 11 Material
Expand/Collapse table rows - Angular 11 Material

Time:04-12

So I'm trying to build a Material data-table with pagination, sorting and filtering in Angular that displays the files that are stored in an Azure storage account. You can download the files that you have selected with the checkboxes on the left.

What I'm currently stuck on is the next step, which is to toggle on expansion and show the description of the file when you click its row accordingly. I've tried to follow What is working is that the extra data shows up when I click on a row, however I would like for it to show up underneath the row, not next to it on the same line and get rid of the whitespace on the right side of the table.

Any help on how to do this would be greatly appreciated, thank you! I don't know if this is just a styling issue or something else but I've been trying to solve this for a long time now and am certain that I missed something somewhere and/or did something wrong.

html

<table mat-table [dataSource]="dataSource"  matSort multiTemplateDataRows>

      <ng-container matColumnDef="select">
        <th  mat-header-cell *matHeaderCellDef>
          <mat-checkbox color="primary" (change)="$event ? selectAllToggle() : null"
                        [checked]="selection.hasValue() && isAllSelected()"
                        [indeterminate]="selection.hasValue() && !isAllSelected()">
          </mat-checkbox>
            <mat-icon  title="Click here to download the selected files" (click)="downloadSelected()" *ngIf="selection.hasValue()">save_alt</mat-icon>
        </th>
        <td mat-cell *matCellDef="let row">
          <mat-checkbox color="primary" (click)="$event.stopPropagation()"
                        (change)="$event ? selection.toggle(row) : null"
                        [checked]="selection.isSelected(row)">
          </mat-checkbox>
        </td>
      </ng-container>

      <ng-container matColumnDef="name">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
        <td mat-cell *matCellDef="let element"> {{element.name}} </td>
      </ng-container>

      <ng-container matColumnDef="createdOn">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> Created On </th>
        <td mat-cell *matCellDef="let element"> {{element.createdOn | date:'shortDate'}} </td>
      </ng-container>

      <ng-container matColumnDef="expandedDetail">
        <td mat-cell *matCellDef="let element" [attr.colspan]="displayedColumns.length">
          <div  [@detailExpand]="element.isExpanded ? 'expanded' : 'collapsed'">
              {{element.fileInfo}}
          </div>
        </td>
      </ng-container>

      <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
      <tr mat-row *matRowDef="let element; columns: displayedColumns;" 
        [class.expanded-row]="element.isExpanded" (click)="toggleRow(element)">
      </tr>
      <tr *matRowDef="let row; columns: ['expandedDetail']" ></tr>

    </table>

ts

import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
import { ApiService } from '../api.services';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { MatSort } from '@angular/material/sort';
import { IBlobData } from '../blob-data';
import { Subscription } from 'rxjs';
import { MatTableDataSource } from '@angular/material/table';
import { HttpErrorResponse } from '@angular/common/http';
import { SelectionModel } from '@angular/cdk/collections';
import { MatPaginator } from '@angular/material/paginator';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css'],
  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)')),
    ]),
  ],
})

export class HomeComponent implements OnInit {

  blobs: any;
  filterBlobs: any[] = [];
  filterTerm: string = ''; 

  private subs = new Subscription();
  
  displayedColumns: any[] = [ 'select', 'name', 'createdOn'];
  selection = new SelectionModel<IBlobData>(true, []);
  public dataSource!: MatTableDataSource<IBlobData>;
  
  constructor(private api: ApiService) { }

  // configure sorting and paginator
  @ViewChild(MatSort, { static: false }) sort!: MatSort;
  @ViewChild('paginator') paginator!: MatPaginator;
  
  async ngOnInit() {
    // subscribe to file data from api
    this.subs.add(this.api.getBlobData()
    .subscribe((res) => {
      this.blobs = res;
      this.dataSource = new MatTableDataSource<IBlobData>(this.blobs); /* fill table with blob data */
      this.dataSource.paginator = this.paginator; /* pagination on table */
      this.dataSource.sort = this.sort; /* sorting on table */

      // filter on table
      this.dataSource.filterPredicate = function (data, filter) {
      return data.name.toLowerCase().includes(filter.toLowerCase());
      }
    },
    (err: HttpErrorResponse) => {
      console.log(err);
    }));
  }

  ngOnDestroy() {
    if (this.subs) {
      this.subs.unsubscribe();
    }
  }

  toggleRow(element: { isExpanded: boolean; }) {
    element.isExpanded = !element.isExpanded;
  }

}

// some functions unrelated to this post where removed

css

table {
  width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  min-width: 500px;
}

th.mat-header-cell {
  text-align: left;
  max-width: 300px;
}

tr.mat-header-row {
  height: 40px !important;
  background-color: whitesmoke;
}

.select-column {
  width: 10%;
}

.download-button {
  margin-left: 15px;
  border: none;
  width: 5%;
  cursor: pointer;
  vertical-align: middle;
}

.detail-row {
  height: 0;
  min-height: auto;
  display: inline-block;
  width: 100%;
}

.element-row td {
  border-bottom-width: 0;
} 

.element-detail {
  overflow: hidden;
  display: flex;
  width: 100%;
}

.detail-table {
  background: #b7b7b773;
  text-align: center;
}

CodePudding user response:

You can use MatExpensionPanel, you've got an example here https://material.angular.io/components/expansion/examples.

  • Related