Expand/Collapse table 行 - Angular 11 Material

Expand/Collapse table rows - Angular 11 Material

所以我正在尝试构建一个 Material data-table,在 Angular 中进行分页、排序和过滤,以显示存储在 Azure 存储帐户中的文件。您可以下载您在左侧的复选框中选择的文件。

我目前坚持的是下一步,即打开扩展并在您相应地单击其行时显示文件的描述。 我尝试遵循 this 教程和其他多个教程,但目前面临以下问题:

有效的是当我点击一行时会显示额外的数据,但是我希望它显示在该行的下方,而不是在同一行的旁边,并去掉右侧的空白table.

如能提供有关如何执行此操作的任何帮助,我们将不胜感激,谢谢! 我不知道这是否只是一个样式问题或其他问题,但我已经尝试解决这个问题很长时间了,并且确定我在某处遗漏了一些东西 and/or 做错了什么。

html

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

      <ng-container matColumnDef="select">
        <th class="select-column" mat-header-cell *matHeaderCellDef>
          <mat-checkbox color="primary" (change)="$event ? selectAllToggle() : null"
                        [checked]="selection.hasValue() && isAllSelected()"
                        [indeterminate]="selection.hasValue() && !isAllSelected()">
          </mat-checkbox>
            <mat-icon class="download-button" 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 class="element-detail" [@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="element-row"
        [class.expanded-row]="element.isExpanded" (click)="toggleRow(element)">
      </tr>
      <tr *matRowDef="let row; columns: ['expandedDetail']" class="detail-row"></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;
}

解决方案: 我使用 material 中的 expansion panel 得到了我想要的结果。

html

<ng-container matColumnDef="name">
            <th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
            <td mat-cell *matCellDef="let element"> 
              <mat-expansion-panel (opened)="element.isExpanded = true"
              (closed)="element.isExpanded = false">
                <mat-expansion-panel-header>
                  <mat-panel-title [ngClass]="element.isExpanded ? 'expanded-title': ''">
                    {{element.name}} 
                  </mat-panel-title>
                </mat-expansion-panel-header>
                <p>{{element.fileInfo}}</p>
              </mat-expansion-panel>
              </td>
          </ng-container>

css

/* overwrite default material styling */
.mat-expansion-panel {
  box-shadow: none !important; 
  padding: 0 !important;
}

.mat-expansion-panel-header {
  padding: 0 20px 0 0!important;
}

.mat-expansion-panel-body {
  padding: 0 !important;
}

ts

/* in my data file */
export interface IData {
    name: string,
    createdOn: string,
    fileInfo: string
    isExpanded: boolean;
}

/* in component.ts file */
isExpanded = false;

您可以使用 MatExpensionPanel,这里有示例 https://material.angular.io/components/expansion/examples